diff options
158 files changed, 2914 insertions, 725 deletions
diff --git a/Android.bp b/Android.bp index 0f9977cb65b3..c22dafb670a3 100644 --- a/Android.bp +++ b/Android.bp @@ -289,6 +289,14 @@ java_defaults { "staledataclass-annotation-processor", "error_prone_android_framework", ], + // Exports needed for staledataclass-annotation-processor, see b/139342589. + javacflags: [ + "-J--add-modules=jdk.compiler", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + ], required: [ // TODO(b/120066492): remove default_television.xml when the build system // propagates "required" properly. diff --git a/ApiDocs.bp b/ApiDocs.bp index c87ecde4e5c8..bf3a6a356e31 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -122,17 +122,30 @@ droidstubs { } droidstubs { - name: "framework-doc-system-stubs", - defaults: ["framework-doc-stubs-sources-default"], + name: "android-non-updatable-doc-stubs-module-lib", + defaults: [ + "android-non-updatable-doc-stubs-defaults", + "module-classpath-stubs-defaults", + ], args: metalava_framework_docs_args + - " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", - api_levels_annotations_enabled: true, - api_levels_annotations_dirs: [ - "sdk-dir", - "api-versions-jars-dir", + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) " + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\) ", + generate_stubs: false, // We're only using this module for the annotations.zip output, disable doc-stubs. + write_sdk_values: false, +} + +droidstubs { + name: "android-non-updatable-doc-stubs-system-server", + defaults: [ + "android-non-updatable-doc-stubs-defaults", + "module-classpath-stubs-defaults", ], - api_levels_sdk_type: "system", - extensions_info_file: ":sdk-extensions-info", + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) " + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\) " + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ", + generate_stubs: false, // We're only using this module for the annotations.zip output, disable doc-stubs. + write_sdk_values: false, } droidstubs { @@ -150,6 +163,20 @@ droidstubs { extensions_info_file: ":sdk-extensions-info", } +droidstubs { + name: "framework-doc-system-stubs", + defaults: ["framework-doc-stubs-sources-default"], + args: metalava_framework_docs_args + + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ", + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", + ], + api_levels_sdk_type: "system", + extensions_info_file: ":sdk-extensions-info", +} + ///////////////////////////////////////////////////////////////////// // API docs are created from the generated stub source files // using droiddoc diff --git a/StubLibraries.bp b/StubLibraries.bp index bc2e6dd79fea..0e084968410f 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -411,6 +411,36 @@ java_library { ], } +java_library { + name: "android_module_stubs_current_with_test_libs", + static_libs: [ + "android_module_lib_stubs_current", + "android.test.base.stubs", + "android.test.mock.stubs", + "android.test.runner.stubs", + ], + defaults: ["android.jar_defaults"], + visibility: [ + "//visibility:override", + "//visibility:private", + ], +} + +java_library { + name: "android_system_server_stubs_current_with_test_libs", + static_libs: [ + "android_system_server_stubs_current", + "android.test.base.stubs.system", + "android.test.mock.stubs.system", + "android.test.runner.stubs.system", + ], + defaults: ["android.jar_defaults"], + visibility: [ + "//visibility:override", + "//visibility:private", + ], +} + droidstubs { name: "api_versions_public", srcs: [":android_stubs_current_with_test_libs{.jar}"], @@ -420,6 +450,7 @@ droidstubs { "sdk-dir", "api-versions-jars-dir", ], + api_levels_sdk_type: "public", extensions_info_file: ":sdk-extensions-info", } @@ -436,6 +467,32 @@ droidstubs { extensions_info_file: ":sdk-extensions-info", } +droidstubs { + name: "api_versions_module_lib", + srcs: [":android_module_stubs_current_with_test_libs{.jar}"], + generate_stubs: false, + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", + ], + api_levels_sdk_type: "module-lib", + extensions_info_file: ":sdk-extensions-info", +} + +droidstubs { + name: "api_versions_system_server", + srcs: [":android_system_server_stubs_current_with_test_libs{.jar}"], + generate_stubs: false, + api_levels_annotations_enabled: true, + api_levels_annotations_dirs: [ + "sdk-dir", + "api-versions-jars-dir", + ], + api_levels_sdk_type: "system-server", + extensions_info_file: ":sdk-extensions-info", +} + ///////////////////////////////////////////////////////////////////// // hwbinder.stubs provides APIs required for building HIDL Java // libraries. diff --git a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java index 34fb88bf8627..10fa8b93acaf 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/StringBuilderPerfTest.java @@ -20,28 +20,19 @@ 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 org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import java.util.Arrays; -import java.util.Collection; /** Tests the performance of various StringBuilder methods. */ -@RunWith(Parameterized.class) +@RunWith(AndroidJUnit4.class) @LargeTest public class StringBuilderPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - @Parameters(name = "mLength={0}") - public static Collection<Object[]> data() { - return Arrays.asList(new Object[][] {{1}, {10}, {100}}); - } - - @Parameterized.Parameter(0) - public int mLength; + public int mLength = 100; @Test public void timeAppendBoolean() { diff --git a/apct-tests/perftests/core/src/android/opengl/perftests/MatrixPerfTest.java b/apct-tests/perftests/core/src/android/opengl/perftests/MatrixPerfTest.java new file mode 100644 index 000000000000..b29614817ee2 --- /dev/null +++ b/apct-tests/perftests/core/src/android/opengl/perftests/MatrixPerfTest.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 android.opengl.perftests; + +import android.opengl.Matrix; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import androidx.test.filters.LargeTest; + +import org.junit.Rule; +import org.junit.Test; + +import java.util.Random; + +@LargeTest +public class MatrixPerfTest { + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Rule + public float[] array = new float[48]; + + @Rule + public float[] bigArray = new float[16 * 1024 * 1024]; + + + @Test + public void testMultiplyMM() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(array, 32, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMMLeftOverlapResult() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(array, 16, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMMRightOverlapResult() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(array, 0, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMMAllOverlap() { + Random rng = new Random(); + for (int i = 0; i < 16; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(array, 0, array, 0, array, 0); + } + } + + @Test + public void testMultiplyMMOutputBigArray() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(bigArray, 1024, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMMAllBigArray() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + bigArray[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMM(bigArray, 1024, bigArray, 16, bigArray, 0); + } + } + + @Test + public void testMultiplyMV() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(array, 20, array, 4, array, 0); + } + } + + @Test + public void testMultiplyMVLeftOverlapResult() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(array, 4, array, 4, array, 0); + } + } + + @Test + public void testMultiplyMVRightOverlapResult() { + Random rng = new Random(); + for (int i = 0; i < 32; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(array, 0, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMVAllOverlap() { + Random rng = new Random(); + for (int i = 0; i < 16; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(array, 0, array, 0, array, 0); + } + } + + @Test + public void testMultiplyMVOutputBigArray() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(bigArray, 1024, array, 16, array, 0); + } + } + + @Test + public void testMultiplyMVAllBigArray() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + bigArray[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.multiplyMV(bigArray, 1024, bigArray, 16, bigArray, 0); + } + } + + @Test + public void testTransposeM() { + Random rng = new Random(); + for (int i = 0; i < 16; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.transposeM(array, 16, array, 0); + } + } + + @Test + public void testInvertM() { + // non-singular matrix + array[ 0] = 0.814f; + array[ 1] = 4.976f; + array[ 2] = -3.858f; + array[ 3] = 7.206f; + array[ 4] = 5.112f; + array[ 5] = -2.420f; + array[ 6] = 8.791f; + array[ 7] = 6.426f; + array[ 8] = 2.945f; + array[ 9] = 1.801f; + array[10] = -2.594f; + array[11] = 2.663f; + array[12] = -5.003f; + array[13] = -4.188f; + array[14] = 3.340f; + array[15] = -1.235f; + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.invertM(array, 16, array, 0); + } + } + + @Test + public void testOrthoM() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.orthoM(array, 0, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); + } + } + + @Test + public void testFrustumM() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.frustumM(array, 0, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); + } + } + + @Test + public void testPerspectiveM() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.perspectiveM(array, 0, 45.0f, 1.0f, 1.0f, 100.0f); + } + } + + @Test + public void testLength() { + Random rng = new Random(); + for (int i = 0; i < 3; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.length(array[0], array[1], array[2]); + } + } + + @Test + public void testSetIdentityM() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.setIdentityM(array, 0); + } + } + + @Test + public void testScaleM() { + Random rng = new Random(); + for (int i = 0; i < 19; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.scaleM(array, 19, array, 0, array[16], array[17], array[18]); + } + } + + @Test + public void testScaleMInPlace() { + Random rng = new Random(); + for (int i = 0; i < 19; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.scaleM(array, 0, array[16], array[17], array[18]); + } + } + + @Test + public void testTranslateM() { + Random rng = new Random(); + for (int i = 0; i < 19; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.translateM(array, 19, array, 0, array[16], array[17], array[18]); + } + } + + @Test + public void testTranslateMInPlace() { + Random rng = new Random(); + for (int i = 0; i < 19; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.translateM(array, 0, array[16], array[17], array[18]); + } + } + + @Test + public void testRotateM() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.rotateM(array, 20, array, 0, array[16], array[17], array[18], array[19]); + } + } + + @Test + public void testRotateMInPlace() { + Random rng = new Random(); + for (int i = 0; i < 20; i++) { + array[i] = rng.nextFloat(); + } + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.rotateM(array, 0, array[16], array[17], array[18], array[19]); + } + } + + @Test + public void testSetRotateM() { + Random rng = new Random(); + array[0] = rng.nextFloat() * 90.0f; + array[1] = rng.nextFloat() + 0.5f; + array[2] = rng.nextFloat() + 0.5f; + array[3] = rng.nextFloat() + 0.5f; + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.setRotateM(array, 4, array[0], array[1], array[2], array[3]); + } + } + + @Test + public void testSetRotateEulerM() { + Random rng = new Random(); + array[0] = rng.nextFloat() * 90.0f; + array[1] = rng.nextFloat() * 90.0f; + array[2] = rng.nextFloat() * 90.0f; + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.setRotateEulerM(array, 3, array[0], array[1], array[2]); + } + } + + @Test + public void testSetLookAtM() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Matrix.setLookAtM(array, 9, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 0.0f); + } + } +} diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 0de0a1cf9c8e..d6b246a9e2e3 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -112,6 +112,7 @@ import android.text.TextUtils; import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.Log; import android.util.LongArrayQueue; @@ -2299,7 +2300,11 @@ public class AlarmManagerService extends SystemService { + " reached for uid: " + UserHandle.formatUid(callingUid) + ", callingPackage: " + callingPackage; Slog.w(TAG, errorMsg); - throw new IllegalStateException(errorMsg); + if (callingUid != Process.SYSTEM_UID) { + throw new IllegalStateException(errorMsg); + } else { + EventLog.writeEvent(0x534e4554, "234441463", -1, errorMsg); + } } setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation, directReceiver, listenerTag, flags, workSource, alarmClock, callingUid, diff --git a/api/Android.bp b/api/Android.bp index 505d7bf99135..210b8f50b803 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -208,6 +208,24 @@ genrule { } genrule { + name: "sdk-annotations-module-lib.zip", + defaults: ["sdk-annotations-defaults"], + srcs: [ + ":android-non-updatable-doc-stubs-module-lib{.annotations.zip}", + ":all-modules-module-lib-annotations", + ], +} + +genrule { + name: "sdk-annotations-system-server.zip", + defaults: ["sdk-annotations-defaults"], + srcs: [ + ":android-non-updatable-doc-stubs-system-server{.annotations.zip}", + ":all-modules-system-server-annotations", + ], +} + +genrule { name: "combined-removed-dex", visibility: [ "//frameworks/base/boot", diff --git a/api/api.go b/api/api.go index f15804156bdf..6a6c493e041a 100644 --- a/api/api.go +++ b/api/api.go @@ -148,18 +148,35 @@ func createMergedStubsSrcjar(ctx android.LoadHookContext, modules []string) { ctx.CreateModule(genrule.GenRuleFactory, &props) } -func createMergedPublicAnnotationsFilegroup(ctx android.LoadHookContext, modules []string) { - props := fgProps{} - props.Name = proptools.StringPtr("all-modules-public-annotations") - props.Srcs = createSrcs(modules, "{.public.annotations.zip}") - ctx.CreateModule(android.FileGroupFactory, &props) -} - -func createMergedSystemAnnotationsFilegroup(ctx android.LoadHookContext, modules []string) { - props := fgProps{} - props.Name = proptools.StringPtr("all-modules-system-annotations") - props.Srcs = createSrcs(modules, "{.system.annotations.zip}") - ctx.CreateModule(android.FileGroupFactory, &props) +func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) { + for _, i := range []struct{ + name string + tag string + modules []string + }{ + { + name: "all-modules-public-annotations", + tag: "{.public.annotations.zip}", + modules: modules, + }, { + name: "all-modules-system-annotations", + tag: "{.system.annotations.zip}", + modules: modules, + }, { + name: "all-modules-module-lib-annotations", + tag: "{.module-lib.annotations.zip}", + modules: modules, + }, { + name: "all-modules-system-server-annotations", + tag: "{.system-server.annotations.zip}", + modules: system_server_modules, + }, + } { + props := fgProps{} + props.Name = proptools.StringPtr(i.name) + props.Srcs = createSrcs(i.modules, i.tag) + ctx.CreateModule(android.FileGroupFactory, &props) + } } func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { @@ -172,17 +189,43 @@ func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { // difficult to achieve. modules = remove(modules, art) - props := genruleProps{} - props.Name = proptools.StringPtr("api-versions-xml-public-filtered") - props.Tools = []string{"api_versions_trimmer"} - props.Out = []string{"api-versions-public-filtered.xml"} - props.Cmd = proptools.StringPtr("$(location api_versions_trimmer) $(out) $(in)") - // 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{":api_versions_public{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...) - props.Dists = []android.Dist{{Targets: []string{"sdk"}}} - ctx.CreateModule(genrule.GenRuleFactory, &props) + for _, i := range []struct{ + name string + out string + in string + }{ + { + // We shouldn't need public-filtered or system-filtered. + // public-filtered is currently used to lint things that + // use the module sdk or the system server sdk, but those + // should be switched over to module-filtered and + // system-server-filtered, and then public-filtered can + // be removed. + name: "api-versions-xml-public-filtered", + out: "api-versions-public-filtered.xml", + in: ":api_versions_public{.api_versions.xml}", + }, { + name: "api-versions-xml-module-lib-filtered", + out: "api-versions-module-lib-filtered.xml", + in: ":api_versions_module_lib{.api_versions.xml}", + }, { + name: "api-versions-xml-system-server-filtered", + out: "api-versions-system-server-filtered.xml", + in: ":api_versions_system_server{.api_versions.xml}", + }, + } { + props := genruleProps{} + props.Name = proptools.StringPtr(i.name) + props.Out = []string{i.out} + // 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{i.in}, createSrcs(modules, ".stubs{.jar}")...) + props.Tools = []string{"api_versions_trimmer"} + props.Cmd = proptools.StringPtr("$(location api_versions_trimmer) $(out) $(in)") + props.Dists = []android.Dist{{Targets: []string{"sdk"}}} + ctx.CreateModule(genrule.GenRuleFactory, &props) + } } func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) { @@ -279,11 +322,12 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { bootclasspath := a.properties.Bootclasspath + system_server_classpath := a.properties.System_server_classpath if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") { bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...) sort.Strings(bootclasspath) } - createMergedTxts(ctx, bootclasspath, a.properties.System_server_classpath) + createMergedTxts(ctx, bootclasspath, system_server_classpath) createMergedStubsSrcjar(ctx, bootclasspath) @@ -292,8 +336,7 @@ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { createMergedFrameworkModuleLibStubs(ctx, bootclasspath) createMergedFrameworkImpl(ctx, bootclasspath) - createMergedPublicAnnotationsFilegroup(ctx, bootclasspath) - createMergedSystemAnnotationsFilegroup(ctx, bootclasspath) + createMergedAnnotationsFilegroups(ctx, bootclasspath, system_server_classpath) createFilteredApiVersions(ctx, bootclasspath) diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index 836801deaa08..5af02f405ed9 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -52,11 +52,7 @@ enum { #define SKIPPED_DUMPSTATE_SECTIONS { \ 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \ 1200, 1201, 1202, /* Native, hal, java traces */ \ - 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, \ - 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3027, 3028, 3029, \ - 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, \ - 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 4000, \ - 4001, /* Dumpsys */ } + 3018, /* dumpsys meminfo*/ } namespace android { namespace os { diff --git a/core/api/current.txt b/core/api/current.txt index 644a194f6ed1..9c7796ef9d4b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -4415,6 +4415,7 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityManager.MemoryInfo> CREATOR; + field public long advertisedMem; field public long availMem; field public boolean lowMemory; field public long threshold; @@ -43490,7 +43491,7 @@ package android.telephony { method public void registerTelephonyCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback); - method @Nullable @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(int, @NonNull android.telephony.NetworkScanRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyScanManager.NetworkScanCallback); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE}) public android.telephony.NetworkScan requestNetworkScan(int, @NonNull android.telephony.NetworkScanRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyScanManager.NetworkScanCallback); method public void sendDialerSpecialCode(String); method public String sendEnvelopeWithStatus(String); method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler); diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS index a31cfae995b2..fb06e236dd8a 100644 --- a/core/java/android/accessibilityservice/OWNERS +++ b/core/java/android/accessibilityservice/OWNERS @@ -1,4 +1,6 @@ -svetoslavganov@google.com pweaver@google.com -rhedjao@google.com ryanlwlin@google.com +danielnorman@google.com +sallyyuen@google.com +aarmaly@google.com +fuego@google.com 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/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5d1d225f4d2d..6f9a98d8313f 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -29,6 +29,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -2813,6 +2814,15 @@ public class ActivityManager { */ public static class MemoryInfo implements Parcelable { /** + * The advertised memory of the system, as the end user would encounter in a retail display + * environment. This value might be different from {@code totalMem}. This could be due to + * many reasons. For example, the ODM could reserve part of the memory for the Trusted + * Execution Environment (TEE) which the kernel doesn't have access or knowledge about it. + */ + @SuppressLint("MutableBareField") + public long advertisedMem; + + /** * The available memory on the system. This number should not * be considered absolute: due to the nature of the kernel, a significant * portion of this memory is actually in use and needed for the overall @@ -2861,6 +2871,7 @@ public class ActivityManager { } public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(advertisedMem); dest.writeLong(availMem); dest.writeLong(totalMem); dest.writeLong(threshold); @@ -2872,6 +2883,7 @@ public class ActivityManager { } public void readFromParcel(Parcel source) { + advertisedMem = source.readLong(); availMem = source.readLong(); totalMem = source.readLong(); threshold = source.readLong(); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 9c0b443bb3c7..07fbde546cbc 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1454,6 +1454,11 @@ public class ActivityOptions extends ComponentOptions { } /** @hide */ + public void setRemoteTransition(@Nullable RemoteTransition remoteTransition) { + mRemoteTransition = remoteTransition; + } + + /** @hide */ public static ActivityOptions fromBundle(Bundle bOptions) { return bOptions != null ? new ActivityOptions(bOptions) : null; } diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 068304d75910..f3fc46869916 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -29,7 +29,7 @@ per-file ProfilerInfo* = file:/services/core/java/com/android/server/am/OWNERS per-file Service* = file:/services/core/java/com/android/server/am/OWNERS per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS -per-file UiAutomation.java = file:/services/accessibility/OWNERS +per-file UiAutomation* = file:/services/accessibility/OWNERS per-file GameManager* = file:/GAME_MANAGER_OWNERS per-file GameState* = file:/GAME_MANAGER_OWNERS per-file IGameManager* = file:/GAME_MANAGER_OWNERS diff --git a/core/java/android/companion/OWNERS b/core/java/android/companion/OWNERS index 004f66caed7b..0348fe2776fe 100644 --- a/core/java/android/companion/OWNERS +++ b/core/java/android/companion/OWNERS @@ -1,5 +1,3 @@ -ewol@google.com evanxinchen@google.com guojing@google.com -svetoslavganov@google.com -sergeynv@google.com
\ No newline at end of file +raphk@google.com
\ No newline at end of file diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index 830584314039..bc6368639baa 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -299,7 +299,7 @@ public final class SQLiteDatabaseConfiguration { if (isLegacyCompatibilityWalEnabled()) { return SQLiteCompatibilityWalFlags.getWALSyncMode(); } else { - return SQLiteGlobal.getDefaultSyncMode(); + return SQLiteGlobal.getWALSyncMode(); } } else { return SQLiteGlobal.getDefaultSyncMode(); diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 0f1b39c01289..17dcc80dd797 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -826,7 +826,9 @@ public abstract class CameraDevice implements AutoCloseable { * <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link * StreamConfigurationMap} and {@code MAX_RES} refers to the maximum resolution {@link - * StreamConfigurationMap}. The same capture request must not mix targets from + * StreamConfigurationMap}. For {@code MAX_RES} streams, {@code MAX} in the {@code Max size} column refers to the maximum size from + * {@link StreamConfigurationMap#getOutputSizes} and {@link StreamConfigurationMap#getHighResolutionOutputSizes}. + * Note: The same capture request must not mix targets from * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p> * * <p> 10-bit output capable diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java index e5b9cdb74d3b..956a474401ba 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -1723,7 +1723,17 @@ public final class MandatoryStreamCombination { } if (isUltraHighResolution) { - sizes.add(getMaxSize(sm.getOutputSizes(formatChosen))); + Size [] outputSizes = sm.getOutputSizes(formatChosen); + Size [] highResolutionOutputSizes = + sm.getHighResolutionOutputSizes(formatChosen); + Size maxBurstSize = getMaxSizeOrNull(outputSizes); + Size maxHighResolutionSize = getMaxSizeOrNull(highResolutionOutputSizes); + Size chosenMaxSize = + maxBurstSize != null ? maxBurstSize : maxHighResolutionSize; + if (maxBurstSize != null && maxHighResolutionSize != null) { + chosenMaxSize = getMaxSize(maxBurstSize, maxHighResolutionSize); + } + sizes.add(chosenMaxSize); } else { if (formatChosen == ImageFormat.RAW_SENSOR) { // RAW_SENSOR always has MAXIMUM threshold. @@ -2126,6 +2136,21 @@ public final class MandatoryStreamCombination { } /** + * Get the largest size by area. + * + * @param sizes an array of sizes + * + * @return Largest Size or null if sizes was null or had 0 elements + */ + public static @Nullable Size getMaxSizeOrNull(Size... sizes) { + if (sizes == null || sizes.length == 0) { + return null; + } + + return getMaxSize(sizes); + } + + /** * Whether or not the hardware level reported by android.info.supportedHardwareLevel is * at least the desired one (but could be higher) */ diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 2b34d8639235..0b56d19201fb 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -209,7 +209,8 @@ public final class CardEmulation { */ public boolean isDefaultServiceForCategory(ComponentName service, String category) { try { - return sService.isDefaultServiceForCategory(mContext.getUserId(), service, category); + return sService.isDefaultServiceForCategory(mContext.getUser().getIdentifier(), + service, category); } catch (RemoteException e) { // Try one more time recoverService(); @@ -218,8 +219,8 @@ public final class CardEmulation { return false; } try { - return sService.isDefaultServiceForCategory(mContext.getUserId(), service, - category); + return sService.isDefaultServiceForCategory(mContext.getUser().getIdentifier(), + service, category); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); return false; @@ -240,7 +241,8 @@ public final class CardEmulation { */ public boolean isDefaultServiceForAid(ComponentName service, String aid) { try { - return sService.isDefaultServiceForAid(mContext.getUserId(), service, aid); + return sService.isDefaultServiceForAid(mContext.getUser().getIdentifier(), + service, aid); } catch (RemoteException e) { // Try one more time recoverService(); @@ -249,7 +251,8 @@ public final class CardEmulation { return false; } try { - return sService.isDefaultServiceForAid(mContext.getUserId(), service, aid); + return sService.isDefaultServiceForAid(mContext.getUser().getIdentifier(), + service, aid); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -348,7 +351,8 @@ public final class CardEmulation { List<String> aids) { AidGroup aidGroup = new AidGroup(aids, category); try { - return sService.registerAidGroupForService(mContext.getUserId(), service, aidGroup); + return sService.registerAidGroupForService(mContext.getUser().getIdentifier(), + service, aidGroup); } catch (RemoteException e) { // Try one more time recoverService(); @@ -357,8 +361,8 @@ public final class CardEmulation { return false; } try { - return sService.registerAidGroupForService(mContext.getUserId(), service, - aidGroup); + return sService.registerAidGroupForService(mContext.getUser().getIdentifier(), + service, aidGroup); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -391,7 +395,7 @@ public final class CardEmulation { } try { - return sService.unsetOffHostForService(mContext.getUserId(), service); + return sService.unsetOffHostForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException e) { // Try one more time recoverService(); @@ -400,7 +404,7 @@ public final class CardEmulation { return false; } try { - return sService.unsetOffHostForService(mContext.getUserId(), service); + return sService.unsetOffHostForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -468,7 +472,7 @@ public final class CardEmulation { } try { - return sService.setOffHostForService(mContext.getUserId(), service, + return sService.setOffHostForService(mContext.getUser().getIdentifier(), service, offHostSecureElement); } catch (RemoteException e) { // Try one more time @@ -478,7 +482,7 @@ public final class CardEmulation { return false; } try { - return sService.setOffHostForService(mContext.getUserId(), service, + return sService.setOffHostForService(mContext.getUser().getIdentifier(), service, offHostSecureElement); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); @@ -503,8 +507,8 @@ public final class CardEmulation { */ public List<String> getAidsForService(ComponentName service, String category) { try { - AidGroup group = sService.getAidGroupForService(mContext.getUserId(), service, - category); + AidGroup group = sService.getAidGroupForService(mContext.getUser().getIdentifier(), + service, category); return (group != null ? group.getAids() : null); } catch (RemoteException e) { recoverService(); @@ -513,8 +517,8 @@ public final class CardEmulation { return null; } try { - AidGroup group = sService.getAidGroupForService(mContext.getUserId(), service, - category); + AidGroup group = sService.getAidGroupForService(mContext.getUser().getIdentifier(), + service, category); return (group != null ? group.getAids() : null); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); @@ -540,7 +544,8 @@ public final class CardEmulation { */ public boolean removeAidsForService(ComponentName service, String category) { try { - return sService.removeAidGroupForService(mContext.getUserId(), service, category); + return sService.removeAidGroupForService(mContext.getUser().getIdentifier(), service, + category); } catch (RemoteException e) { // Try one more time recoverService(); @@ -549,7 +554,8 @@ public final class CardEmulation { return false; } try { - return sService.removeAidGroupForService(mContext.getUserId(), service, category); + return sService.removeAidGroupForService(mContext.getUser().getIdentifier(), + service, category); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -684,7 +690,8 @@ public final class CardEmulation { @Nullable public List<String> getAidsForPreferredPaymentService() { try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); + ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( + mContext.getUser().getIdentifier()); return (serviceInfo != null ? serviceInfo.getAids() : null); } catch (RemoteException e) { recoverService(); @@ -694,7 +701,7 @@ public final class CardEmulation { } try { ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUserId()); + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); return (serviceInfo != null ? serviceInfo.getAids() : null); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); @@ -723,7 +730,8 @@ public final class CardEmulation { @Nullable public String getRouteDestinationForPreferredPaymentService() { try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); + ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( + mContext.getUser().getIdentifier()); if (serviceInfo != null) { if (!serviceInfo.isOnHost()) { return serviceInfo.getOffHostSecureElement() == null ? @@ -740,7 +748,7 @@ public final class CardEmulation { } try { ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUserId()); + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); if (serviceInfo != null) { if (!serviceInfo.isOnHost()) { return serviceInfo.getOffHostSecureElement() == null ? @@ -766,7 +774,8 @@ public final class CardEmulation { @Nullable public CharSequence getDescriptionForPreferredPaymentService() { try { - ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); + ApduServiceInfo serviceInfo = sService.getPreferredPaymentService( + mContext.getUser().getIdentifier()); return (serviceInfo != null ? serviceInfo.getDescription() : null); } catch (RemoteException e) { recoverService(); @@ -776,7 +785,7 @@ public final class CardEmulation { } try { ApduServiceInfo serviceInfo = - sService.getPreferredPaymentService(mContext.getUserId()); + sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); return (serviceInfo != null ? serviceInfo.getDescription() : null); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); @@ -790,7 +799,8 @@ public final class CardEmulation { */ public boolean setDefaultServiceForCategory(ComponentName service, String category) { try { - return sService.setDefaultServiceForCategory(mContext.getUserId(), service, category); + return sService.setDefaultServiceForCategory(mContext.getUser().getIdentifier(), + service, category); } catch (RemoteException e) { // Try one more time recoverService(); @@ -799,8 +809,8 @@ public final class CardEmulation { return false; } try { - return sService.setDefaultServiceForCategory(mContext.getUserId(), service, - category); + return sService.setDefaultServiceForCategory(mContext.getUser().getIdentifier(), + service, category); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -813,7 +823,7 @@ public final class CardEmulation { */ public boolean setDefaultForNextTap(ComponentName service) { try { - return sService.setDefaultForNextTap(mContext.getUserId(), service); + return sService.setDefaultForNextTap(mContext.getUser().getIdentifier(), service); } catch (RemoteException e) { // Try one more time recoverService(); @@ -822,7 +832,7 @@ public final class CardEmulation { return false; } try { - return sService.setDefaultForNextTap(mContext.getUserId(), service); + return sService.setDefaultForNextTap(mContext.getUser().getIdentifier(), service); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -857,7 +867,7 @@ public final class CardEmulation { */ public List<ApduServiceInfo> getServices(String category) { try { - return sService.getServices(mContext.getUserId(), category); + return sService.getServices(mContext.getUser().getIdentifier(), category); } catch (RemoteException e) { // Try one more time recoverService(); @@ -866,7 +876,7 @@ public final class CardEmulation { return null; } try { - return sService.getServices(mContext.getUserId(), category); + return sService.getServices(mContext.getUser().getIdentifier(), category); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return null; diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java index 557e41a2b103..3c924556365e 100644 --- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java +++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java @@ -117,7 +117,7 @@ public final class NfcFCardEmulation { throw new NullPointerException("service is null"); } try { - return sService.getSystemCodeForService(mContext.getUserId(), service); + return sService.getSystemCodeForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException e) { // Try one more time recoverService(); @@ -126,7 +126,8 @@ public final class NfcFCardEmulation { return null; } try { - return sService.getSystemCodeForService(mContext.getUserId(), service); + return sService.getSystemCodeForService(mContext.getUser().getIdentifier(), + service); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); ee.rethrowAsRuntimeException(); @@ -163,7 +164,7 @@ public final class NfcFCardEmulation { throw new NullPointerException("service or systemCode is null"); } try { - return sService.registerSystemCodeForService(mContext.getUserId(), + return sService.registerSystemCodeForService(mContext.getUser().getIdentifier(), service, systemCode); } catch (RemoteException e) { // Try one more time @@ -173,7 +174,7 @@ public final class NfcFCardEmulation { return false; } try { - return sService.registerSystemCodeForService(mContext.getUserId(), + return sService.registerSystemCodeForService(mContext.getUser().getIdentifier(), service, systemCode); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); @@ -194,7 +195,7 @@ public final class NfcFCardEmulation { throw new NullPointerException("service is null"); } try { - return sService.removeSystemCodeForService(mContext.getUserId(), service); + return sService.removeSystemCodeForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException e) { // Try one more time recoverService(); @@ -203,7 +204,8 @@ public final class NfcFCardEmulation { return false; } try { - return sService.removeSystemCodeForService(mContext.getUserId(), service); + return sService.removeSystemCodeForService(mContext.getUser().getIdentifier(), + service); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); ee.rethrowAsRuntimeException(); @@ -229,7 +231,7 @@ public final class NfcFCardEmulation { throw new NullPointerException("service is null"); } try { - return sService.getNfcid2ForService(mContext.getUserId(), service); + return sService.getNfcid2ForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException e) { // Try one more time recoverService(); @@ -238,7 +240,7 @@ public final class NfcFCardEmulation { return null; } try { - return sService.getNfcid2ForService(mContext.getUserId(), service); + return sService.getNfcid2ForService(mContext.getUser().getIdentifier(), service); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); ee.rethrowAsRuntimeException(); @@ -272,7 +274,7 @@ public final class NfcFCardEmulation { throw new NullPointerException("service or nfcid2 is null"); } try { - return sService.setNfcid2ForService(mContext.getUserId(), + return sService.setNfcid2ForService(mContext.getUser().getIdentifier(), service, nfcid2); } catch (RemoteException e) { // Try one more time @@ -282,7 +284,7 @@ public final class NfcFCardEmulation { return false; } try { - return sService.setNfcid2ForService(mContext.getUserId(), + return sService.setNfcid2ForService(mContext.getUser().getIdentifier(), service, nfcid2); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); @@ -380,7 +382,7 @@ public final class NfcFCardEmulation { */ public List<NfcFServiceInfo> getNfcFServices() { try { - return sService.getNfcFServices(mContext.getUserId()); + return sService.getNfcFServices(mContext.getUser().getIdentifier()); } catch (RemoteException e) { // Try one more time recoverService(); @@ -389,7 +391,7 @@ public final class NfcFCardEmulation { return null; } try { - return sService.getNfcFServices(mContext.getUserId()); + return sService.getNfcFServices(mContext.getUser().getIdentifier()); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return null; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index edfcb3d6f12a..d5c3de146015 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -54,6 +54,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; import android.text.TextUtils; +import android.util.DataUnit; import android.util.Log; import android.util.Slog; import android.webkit.MimeTypeMap; @@ -83,6 +84,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -1309,6 +1311,85 @@ public final class FileUtils { return val * pow; } + private static long toBytes(long value, String unit) { + unit = unit.toUpperCase(); + + if (List.of("B").contains(unit)) { + return value; + } + + if (List.of("K", "KB").contains(unit)) { + return DataUnit.KILOBYTES.toBytes(value); + } + + if (List.of("M", "MB").contains(unit)) { + return DataUnit.MEGABYTES.toBytes(value); + } + + if (List.of("G", "GB").contains(unit)) { + return DataUnit.GIGABYTES.toBytes(value); + } + + if (List.of("KI", "KIB").contains(unit)) { + return DataUnit.KIBIBYTES.toBytes(value); + } + + if (List.of("MI", "MIB").contains(unit)) { + return DataUnit.MEBIBYTES.toBytes(value); + } + + if (List.of("GI", "GIB").contains(unit)) { + return DataUnit.GIBIBYTES.toBytes(value); + } + + return Long.MIN_VALUE; + } + + /** + * @param fmtSize The string that contains the size to be parsed. The + * expected format is: + * + * <p>"^((\\s*[-+]?[0-9]+)\\s*(B|K|KB|M|MB|G|GB|Ki|KiB|Mi|MiB|Gi|GiB)\\s*)$" + * + * <p>For example: 10Kb, 500GiB, 100mb. The unit is not case sensitive. + * + * @return the size in bytes. If {@code fmtSize} has invalid format, it + * returns {@link Long#MIN_VALUE}. + * @hide + */ + public static long parseSize(@Nullable String fmtSize) { + if (fmtSize == null || fmtSize.isBlank()) { + return Long.MIN_VALUE; + } + + int sign = 1; + fmtSize = fmtSize.trim(); + char first = fmtSize.charAt(0); + if (first == '-' || first == '+') { + if (first == '-') { + sign = -1; + } + + fmtSize = fmtSize.replace(first + "", ""); + } + + int index = 0; + // Find the last index of the value in fmtSize. + while (index < fmtSize.length() && Character.isDigit(fmtSize.charAt(index))) { + index++; + } + + // Check if number and units are present. + if (index == 0 || index == fmtSize.length()) { + return Long.MIN_VALUE; + } + + long value = sign * Long.valueOf(fmtSize.substring(0, index)); + String unit = fmtSize.substring(index).trim(); + + return toBytes(value, unit); + } + /** * Closes the given object quietly, ignoring any checked exceptions. Does * nothing if the given object is {@code null}. diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 56652f57e6f1..a6ae663dabb0 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -560,7 +560,9 @@ public final class Parcel { */ public final void recycle() { if (mRecycled) { - Log.w(TAG, "Recycle called on unowned Parcel. (recycle twice?)", mStack); + Log.w(TAG, "Recycle called on unowned Parcel. (recycle twice?) Here: " + + Log.getStackTraceString(new Throwable()) + + " Original recycle call (if DEBUG_RECYCLE): ", mStack); } mRecycled = true; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index e06e7326a860..b3afaecca849 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -26,6 +26,7 @@ import android.annotation.TestApi; import android.annotation.UptimeMillisLong; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build.VERSION_CODES; +import android.sysprop.MemoryProperties; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -1336,6 +1337,24 @@ public class Process { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static final native void sendSignalQuiet(int pid, int signal); + /** + * @return The advertised memory of the system, as the end user would encounter in a retail + * display environment. If the advertised memory is not defined, it returns + * {@code getTotalMemory()} rounded. + * + * @hide + */ + public static final long getAdvertisedMem() { + String formatSize = MemoryProperties.memory_ddr_size().orElse("0KB"); + long memSize = FileUtils.parseSize(formatSize); + + if (memSize == Long.MIN_VALUE) { + return FileUtils.roundStorageSize(getTotalMemory()); + } + + return memSize; + } + /** @hide */ @UnsupportedAppUsage public static final native long getFreeMemory(); diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 7b9ef726b1a3..466ac7895710 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -377,6 +377,14 @@ public final class DeviceConfig { public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness"; /** + * Namespace for Remote Key Provisioning related features. + * + * @hide + */ + public static final String NAMESPACE_REMOTE_KEY_PROVISIONING_NATIVE = + "remote_key_provisioning_native"; + + /** * Namespace for Rollback flags that are applied immediately. * * @hide diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 8efc5eb6b6ff..e720f1ab1523 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -65,6 +65,7 @@ public final class KeymasterDefs { public static final int KM_TAG_PADDING = Tag.PADDING; // KM_ENUM_REP | 6; public static final int KM_TAG_CALLER_NONCE = Tag.CALLER_NONCE; // KM_BOOL | 7; public static final int KM_TAG_MIN_MAC_LENGTH = Tag.MIN_MAC_LENGTH; // KM_UINT | 8; + public static final int KM_TAG_EC_CURVE = Tag.EC_CURVE; // KM_ENUM | 10; public static final int KM_TAG_RSA_PUBLIC_EXPONENT = Tag.RSA_PUBLIC_EXPONENT; // KM_ULONG | 200; public static final int KM_TAG_INCLUDE_UNIQUE_ID = Tag.INCLUDE_UNIQUE_ID; // KM_BOOL | 202; diff --git a/core/java/android/service/resumeonreboot/OWNERS b/core/java/android/service/resumeonreboot/OWNERS index 721fbaf2d4ed..e09805310bbb 100644 --- a/core/java/android/service/resumeonreboot/OWNERS +++ b/core/java/android/service/resumeonreboot/OWNERS @@ -1 +1,2 @@ -ejyzhang@google.com
\ No newline at end of file +aveena@google.com +ejyzhang@google.com diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS index 0b51b2d90b79..a6be687ab4c9 100644 --- a/core/java/android/text/OWNERS +++ b/core/java/android/text/OWNERS @@ -1,4 +1,10 @@ set noparent +halilibo@google.com +haoyuchang@google.com +justinghan@google.com +klippenstein@google.com +nona@google.com +seanmcq@google.com siyamed@google.com -nona@google.com
\ No newline at end of file +soboleva@google.com diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS index b1d3967a8b04..73d134146c3f 100644 --- a/core/java/android/view/accessibility/OWNERS +++ b/core/java/android/view/accessibility/OWNERS @@ -10,3 +10,7 @@ ogunwale@google.com jjaggi@google.com pweaver@google.com ryanlwlin@google.com +danielnorman@google.com +sallyyuen@google.com +aarmaly@google.com +fuego@google.com diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS index 56310aef7752..02dafd44d3bd 100644 --- a/core/java/android/widget/OWNERS +++ b/core/java/android/widget/OWNERS @@ -8,8 +8,8 @@ siyamed@google.com mount@google.com njawad@google.com -per-file TextView*,EditText.java,Editor.java,EditorTouchState.java = file:../text/OWNERS +per-file TextView*,Edit*,Selection* = file:../text/OWNERS per-file SpellChecker.java = file:../view/inputmethod/OWNERS -per-file RemoteViews* = file:../appwidget/OWNERS
\ No newline at end of file +per-file RemoteViews* = file:../appwidget/OWNERS diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 2879cd888d2d..bc7e31fac222 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1598,7 +1598,13 @@ public class RemoteViews implements Parcelable, Filter { public BitmapCache(Parcel source) { mBitmaps = source.createTypedArrayList(Bitmap.CREATOR); - mBitmapHashes = source.readSparseIntArray(); + mBitmapHashes = new SparseIntArray(); + for (int i = 0; i < mBitmaps.size(); i++) { + Bitmap b = mBitmaps.get(i); + if (b != null) { + mBitmapHashes.put(b.hashCode(), i); + } + } } public int getBitmapId(Bitmap b) { @@ -1614,7 +1620,7 @@ public class RemoteViews implements Parcelable, Filter { b = b.asShared(); } mBitmaps.add(b); - mBitmapHashes.put(mBitmaps.size() - 1, hash); + mBitmapHashes.put(hash, mBitmaps.size() - 1); mBitmapMemory = -1; return (mBitmaps.size() - 1); } @@ -1631,7 +1637,6 @@ public class RemoteViews implements Parcelable, Filter { public void writeBitmapsToParcel(Parcel dest, int flags) { dest.writeTypedList(mBitmaps, flags); - dest.writeSparseIntArray(mBitmapHashes); } public int getBitmapMemory() { diff --git a/core/java/com/android/internal/accessibility/OWNERS b/core/java/com/android/internal/accessibility/OWNERS index b3c09e9d539a..0955e005791e 100644 --- a/core/java/com/android/internal/accessibility/OWNERS +++ b/core/java/com/android/internal/accessibility/OWNERS @@ -1,4 +1,6 @@ # Bug component: 44214 -svetoslavganov@google.com pweaver@google.com -qasid@google.com +danielnorman@google.com +sallyyuen@google.com +aarmaly@google.com +fuego@google.com diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java index 627631a376f7..62c7966bb2d6 100644 --- a/core/java/com/android/internal/display/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java @@ -115,7 +115,7 @@ public class BrightnessSynchronizer { Slog.i(TAG, "Setting initial brightness to default value of: " + defaultBrightness); } - mBrightnessSyncObserver.startObserving(); + mBrightnessSyncObserver.startObserving(mHandler); mHandler.sendEmptyMessageAtTime(MSG_RUN_UPDATE, mClock.uptimeMillis()); } @@ -482,27 +482,29 @@ public class BrightnessSynchronizer { } }; - private final ContentObserver mContentObserver = new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange, Uri uri) { - if (selfChange) { - return; - } - if (BRIGHTNESS_URI.equals(uri)) { - handleBrightnessChangeInt(getScreenBrightnessInt()); + private ContentObserver createBrightnessContentObserver(Handler handler) { + return new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange, Uri uri) { + if (selfChange) { + return; + } + if (BRIGHTNESS_URI.equals(uri)) { + handleBrightnessChangeInt(getScreenBrightnessInt()); + } } - } - }; + }; + } boolean isObserving() { return mIsObserving; } - void startObserving() { + void startObserving(Handler handler) { final ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(BRIGHTNESS_URI, false, mContentObserver, - UserHandle.USER_ALL); - mDisplayManager.registerDisplayListener(mListener, mHandler, + cr.registerContentObserver(BRIGHTNESS_URI, false, + createBrightnessContentObserver(handler), UserHandle.USER_ALL); + mDisplayManager.registerDisplayListener(mListener, handler, DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS); mIsObserving = true; } diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index b866723954b5..b11ea2961c17 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -25,6 +25,7 @@ import android.graphics.ImageDecoder; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; +import android.text.TextUtils; import android.util.Log; import android.util.Size; @@ -108,6 +109,12 @@ public class LocalImageResolver { } break; case Icon.TYPE_RESOURCE: + if (!(TextUtils.isEmpty(icon.getResPackage()) + || context.getPackageName().equals(icon.getResPackage()))) { + // We can't properly resolve icons from other packages here, so fall back. + return icon.loadDrawable(context); + } + Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight); if (result != null) { return tintDrawable(icon, result); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 88aa4de0db24..77317d1c3c1a 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2179,7 +2179,7 @@ static jint convertAudioMixToNative(JNIEnv *env, break; } - nAudioMix->mCriteria.add(nCriterion); + nAudioMix->mCriteria.push_back(nCriterion); env->DeleteLocalRef(jCriterion); } diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index bb4ab39a59d1..1f64df49cb56 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -101,9 +101,18 @@ static void android_os_Parcel_markSensitive(jlong nativePtr) static void android_os_Parcel_markForBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject binder) { + LOG_ALWAYS_FATAL_IF(binder == nullptr, "Null binder specified for markForBinder"); + Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel) { - parcel->markForBinder(ibinderForJavaObject(env, binder)); + sp<IBinder> nBinder = ibinderForJavaObject(env, binder); + + if (nBinder == nullptr) { + ALOGE("Native binder in markForBinder is null for non-null jobject"); + return; + } + + parcel->markForBinder(nBinder); } } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index f28e2f636dac..9f88f3369ae8 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -798,6 +798,12 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); + + if (jbh == nullptr) { + ALOGE("JavaBBinderHolder null on binder"); + return nullptr; + } + return jbh->get(env, obj); } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d689aab96ce9..6f83ab169b5f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1995,6 +1995,9 @@ on grouped devices. --> <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool> + <!-- Flag indicating current media Output Switcher version. --> + <integer name="config_mediaOutputSwitchDialogVersion">1</integer> + <!-- Flag indicating that an outbound call must have a call capable phone account that has declared it can process the call's handle. --> <bool name="config_requireCallCapableAccountForHandle">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 234c43525a01..1f71bf9f95dd 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4703,6 +4703,8 @@ <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" /> + <java-symbol type="integer" name="config_mediaOutputSwitchDialogVersion" /> + <!-- List of shared library packages that should be loaded by the classloader after the code and resources provided by applications. --> <java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" /> diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java index c1e72fe75666..5f731e201866 100644 --- a/core/tests/coretests/src/android/os/FileUtilsTest.java +++ b/core/tests/coretests/src/android/os/FileUtilsTest.java @@ -58,10 +58,10 @@ import android.provider.DocumentsContract.Document; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import libcore.io.Streams; - import com.google.android.collect.Sets; +import libcore.io.Streams; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -524,6 +524,56 @@ public class FileUtilsTest { } @Test + public void testParseSize() { + assertEquals(0L, FileUtils.parseSize("0MB")); + assertEquals(1_024L, FileUtils.parseSize("1024b")); + assertEquals(-1L, FileUtils.parseSize(" -1 b ")); + assertEquals(0L, FileUtils.parseSize(" -0 gib ")); + assertEquals(1_000L, FileUtils.parseSize("1K")); + assertEquals(1_000L, FileUtils.parseSize("1KB")); + assertEquals(10_000L, FileUtils.parseSize("10KB")); + assertEquals(100_000L, FileUtils.parseSize("100KB")); + assertEquals(1_000_000L, FileUtils.parseSize("1000KB")); + assertEquals(1_024_000L, FileUtils.parseSize("1000KiB")); + assertEquals(70_000_000L, FileUtils.parseSize("070M")); + assertEquals(70_000_000L, FileUtils.parseSize("070MB")); + assertEquals(73_400_320L, FileUtils.parseSize("70MiB")); + assertEquals(700_000_000L, FileUtils.parseSize("700000KB")); + assertEquals(200_000_000L, FileUtils.parseSize("+200MB")); + assertEquals(1_000_000_000L, FileUtils.parseSize("1000MB")); + assertEquals(1_000_000_000L, FileUtils.parseSize("+1000 mb")); + assertEquals(644_245_094_400L, FileUtils.parseSize("600GiB")); + assertEquals(999_000_000_000L, FileUtils.parseSize("999GB")); + assertEquals(999_000_000_000L, FileUtils.parseSize("999 gB")); + assertEquals(9_999_000_000_000L, FileUtils.parseSize("9999GB")); + assertEquals(9_000_000_000_000L, FileUtils.parseSize(" 9000 GB ")); + assertEquals(1_234_000_000_000L, FileUtils.parseSize(" 1234 GB ")); + assertEquals(1_234_567_890_000L, FileUtils.parseSize(" 1234567890 KB ")); + } + + @Test + public void testParseSize_invalidArguments() { + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(null)); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("null")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("KB")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("123 dd")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("Invalid")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" ABC890 KB ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("-=+90 KB ")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("--123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("-KB")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("++123")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+ 1 +")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("+--+ 1 +")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize("1GB+")); + assertEquals(Long.MIN_VALUE, FileUtils.parseSize(" + 1234567890 KB ")); + } + + @Test public void testTranslateMode() throws Exception { assertTranslate("r", O_RDONLY, MODE_READ_ONLY); diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java index ae4edb97aab0..52846dfbb14b 100644 --- a/core/tests/coretests/src/android/os/ProcessTest.java +++ b/core/tests/coretests/src/android/os/ProcessTest.java @@ -72,4 +72,7 @@ public class ProcessTest extends TestCase { assertEquals(-1, Process.getThreadGroupLeader(BAD_PID)); } + public void testGetAdvertisedMem() { + assertTrue(Process.getTotalMemory() <= Process.getAdvertisedMem()); + } } diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java index c63d18bfa531..0cee526651a6 100644 --- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java @@ -270,4 +270,13 @@ public class LocalImageResolverTest { assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight); } + + @Test + public void resolveImage_iconWithOtherPackageResource_usesPackageContextDefinition() + throws IOException { + Icon icon = Icon.createWithResource("this_is_invalid", R.drawable.test32x24); + Drawable d = LocalImageResolver.resolveImage(icon, mContext); + // This drawable must not be loaded - if it was, the code ignored the package specification. + assertThat(d).isNull(); + } } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 392d89e4fc6a..8ca16071a1e4 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -483,6 +483,8 @@ applications that come with the platform <permission name="android.permission.NOTIFY_PENDING_SYSTEM_UPDATE" /> <!-- Permission required for GTS test - GtsAssistIntentTestCases --> <permission name="android.permission.MANAGE_VOICE_KEYPHRASES" /> + <!-- Permission required for test - CellBroadcastComplianceTest --> + <permission name="com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY" /> <!-- Permission required for ATS test - CarDevicePolicyManagerTest --> <permission name="android.permission.LOCK_DEVICE" /> <!-- Permissions required for CTS test - CtsSafetyCenterTestCases --> diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java index b631999c2c54..4e73bd9d3c82 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java @@ -18,13 +18,19 @@ package android.security.keystore2; import android.annotation.NonNull; import android.security.KeyStoreSecurityLevel; +import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyProperties; +import android.system.keystore2.Authorization; import android.system.keystore2.KeyDescriptor; import android.system.keystore2.KeyMetadata; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; +import java.security.spec.InvalidParameterSpecException; /** * {@link ECPublicKey} backed by keystore. @@ -56,11 +62,45 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme } } + private static String getEcCurveFromKeymaster(int ecCurve) { + switch (ecCurve) { + case android.hardware.security.keymint.EcCurve.P_224: + return "secp224r1"; + case android.hardware.security.keymint.EcCurve.P_256: + return "secp256r1"; + case android.hardware.security.keymint.EcCurve.P_384: + return "secp384r1"; + case android.hardware.security.keymint.EcCurve.P_521: + return "secp521r1"; + } + return ""; + } + + private ECParameterSpec getCurveSpec(String name) + throws NoSuchAlgorithmException, InvalidParameterSpecException { + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); + parameters.init(new ECGenParameterSpec(name)); + return parameters.getParameterSpec(ECParameterSpec.class); + } + @Override public AndroidKeyStorePrivateKey getPrivateKey() { + ECParameterSpec params = mParams; + for (Authorization a : getAuthorizations()) { + try { + if (a.keyParameter.tag == KeymasterDefs.KM_TAG_EC_CURVE) { + params = getCurveSpec(getEcCurveFromKeymaster( + a.keyParameter.value.getEcCurve())); + break; + } + } catch (Exception e) { + throw new RuntimeException("Unable to parse EC curve " + + a.keyParameter.value.getEcCurve()); + } + } return new AndroidKeyStoreECPrivateKey( getUserKeyDescriptor(), getKeyIdDescriptor().nspace, getAuthorizations(), - getSecurityLevel(), mParams); + getSecurityLevel(), params); } @Override diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java index b1338d164055..4caa47f2078b 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java @@ -31,6 +31,8 @@ import java.security.NoSuchAlgorithmException; import java.security.ProviderException; import java.security.PublicKey; import java.security.SecureRandom; +import java.security.interfaces.ECKey; +import java.security.interfaces.XECKey; import java.security.spec.AlgorithmParameterSpec; import java.util.ArrayList; import java.util.List; @@ -132,6 +134,15 @@ public class AndroidKeyStoreKeyAgreementSpi extends KeyAgreementSpi throw new InvalidKeyException("key == null"); } else if (!(key instanceof PublicKey)) { throw new InvalidKeyException("Only public keys supported. Key: " + key); + } else if (!(mKey instanceof ECKey && key instanceof ECKey) + && !(mKey instanceof XECKey && key instanceof XECKey)) { + throw new InvalidKeyException( + "Public and Private key should be of the same type:"); + } else if (mKey instanceof ECKey + && !((ECKey) key).getParams().getCurve() + .equals(((ECKey) mKey).getParams().getCurve())) { + throw new InvalidKeyException( + "Public and Private key parameters should be same."); } else if (!lastPhase) { throw new IllegalStateException( "Only one other party supported. lastPhase must be set to true."); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java index 42589640d2b7..e392c8dcca93 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java @@ -22,16 +22,18 @@ import android.system.keystore2.Authorization; import android.system.keystore2.KeyDescriptor; import java.security.PrivateKey; -import java.security.interfaces.EdECKey; +import java.security.interfaces.XECPrivateKey; import java.security.spec.NamedParameterSpec; +import java.util.Optional; /** * X25519 Private Key backed by Keystore. - * instance of {@link PrivateKey} and {@link EdECKey} + * instance of {@link PrivateKey} and {@link XECPrivateKey} * * @hide */ -public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey { +public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey + implements XECPrivateKey { public AndroidKeyStoreXDHPrivateKey( @NonNull KeyDescriptor descriptor, long keyId, @NonNull Authorization[] authorizations, @@ -44,4 +46,12 @@ public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey impl public NamedParameterSpec getParams() { return NamedParameterSpec.X25519; } + + @Override + public Optional<byte[]> getScalar() { + /* An empty Optional if the scalar cannot be extracted (e.g. if the provider is a hardware + * token and the private key is not allowed to leave the crypto boundary). + */ + return Optional.empty(); + } } diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index a5c0924579eb..b763a96e8e8a 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -169,6 +169,8 @@ void DeferredLayerUpdater::apply() { sk_sp<SkImage> layerImage = mImageSlots[slot].createIfNeeded( hardwareBuffer, dataspace, newContent, mRenderState.getRenderThread().getGrContext()); + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(hardwareBuffer, &bufferDesc); // unref to match the ref added by ASurfaceTexture_dequeueBuffer. eglCreateImageKHR // (invoked by createIfNeeded) will add a ref to the AHardwareBuffer. AHardwareBuffer_release(hardwareBuffer); @@ -189,6 +191,7 @@ void DeferredLayerUpdater::apply() { maxLuminanceNits = std::max(cta861_3.maxContentLightLevel, maxLuminanceNits); } + mLayer->setBufferFormat(bufferDesc.format); updateLayer(forceFilter, layerImage, outTransform, currentCropRect, maxLuminanceNits); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 47eb5d3bfb83..345749b6d920 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -102,6 +102,10 @@ public: inline float getMaxLuminanceNits() { return mMaxLuminanceNits; } + void setBufferFormat(uint32_t format) { mBufferFormat = format; } + + uint32_t getBufferFormat() const { return mBufferFormat; } + void draw(SkCanvas* canvas); protected: @@ -169,6 +173,8 @@ private: */ float mMaxLuminanceNits = -1; + uint32_t mBufferFormat = 0; + }; // struct Layer } // namespace uirenderer diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 2fba13c3cfea..3ba540921f64 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -107,6 +107,32 @@ static bool isHdrDataspace(ui::Dataspace dataspace) { return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG; } +static void adjustCropForYUV(uint32_t format, int bufferWidth, int bufferHeight, SkRect* cropRect) { + // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by + // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an + // additional 0.5 inset. See GLConsumer::computeTransformMatrix for details. + float shrinkAmount = 0.0f; + switch (format) { + // Use HAL formats since some AHB formats are only available in vndk + case HAL_PIXEL_FORMAT_YCBCR_420_888: + case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + shrinkAmount = 0.5f; + break; + default: + break; + } + + // Shrink the crop if it has more than 1-px and differs from the buffer size. + if (cropRect->width() > 1 && cropRect->width() < bufferWidth) { + cropRect->inset(shrinkAmount, 0); + } + + if (cropRect->height() > 1 && cropRect->height() < bufferHeight) { + cropRect->inset(0, shrinkAmount); + } +} + // TODO: Context arg probably doesn't belong here – do debug check at callsite instead. bool LayerDrawable::DrawLayer(GrRecordingContext* context, SkCanvas* canvas, @@ -142,6 +168,7 @@ bool LayerDrawable::DrawLayer(GrRecordingContext* context, SkRect skiaSrcRect; if (srcRect && !srcRect->isEmpty()) { skiaSrcRect = *srcRect; + adjustCropForYUV(layer->getBufferFormat(), imageWidth, imageHeight, &skiaSrcRect); } else { skiaSrcRect = SkRect::MakeIWH(imageWidth, imageHeight); } diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 59c914f0198c..03f02de98efe 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -243,7 +243,9 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { mContext->unpinImages(); for (size_t i = 0; i < mLayers.size(); i++) { - mLayers[i]->apply(); + if (mLayers[i]) { + mLayers[i]->apply(); + } } mLayers.clear(); mContext->setContentDrawBounds(mContentDrawBounds); diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp index 547d7192090a..ff1714da2008 100644 --- a/libs/incident/Android.bp +++ b/libs/incident/Android.bp @@ -133,4 +133,6 @@ cc_test { static_libs: [ "libgmock", ], + + host_required: ["compatibility-tradefed"], } diff --git a/media/Android.bp b/media/Android.bp index e97f077b347a..97970dae0fa0 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -90,8 +90,13 @@ aidl_interface { "aidl/android/media/audio/common/AudioStreamType.aidl", "aidl/android/media/audio/common/AudioUsage.aidl", "aidl/android/media/audio/common/AudioUuid.aidl", + "aidl/android/media/audio/common/Boolean.aidl", + "aidl/android/media/audio/common/Byte.aidl", "aidl/android/media/audio/common/ExtraAudioDescriptor.aidl", + "aidl/android/media/audio/common/Float.aidl", + "aidl/android/media/audio/common/Double.aidl", "aidl/android/media/audio/common/Int.aidl", + "aidl/android/media/audio/common/Long.aidl", "aidl/android/media/audio/common/PcmType.aidl", ], stability: "vintf", diff --git a/media/aidl/android/media/audio/common/Boolean.aidl b/media/aidl/android/media/audio/common/Boolean.aidl new file mode 100644 index 000000000000..fddd5324c534 --- /dev/null +++ b/media/aidl/android/media/audio/common/Boolean.aidl @@ -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 android.media.audio.common; + +/** + * This is a simple wrapper around a 'boolean', putting it in a parcelable, so it + * can be used as an 'inout' parameter, be made '@nullable', etc. + * + * {@hide} + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable Boolean { + boolean value; +} diff --git a/media/aidl/android/media/audio/common/Byte.aidl b/media/aidl/android/media/audio/common/Byte.aidl new file mode 100644 index 000000000000..f0a31a2818bf --- /dev/null +++ b/media/aidl/android/media/audio/common/Byte.aidl @@ -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 android.media.audio.common; + +/** + * This is a simple wrapper around a 'byte', putting it in a parcelable, so it + * can be used as an 'inout' parameter, be made '@nullable', etc. + * + * {@hide} + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable Byte { + byte value; +} diff --git a/media/aidl/android/media/audio/common/Double.aidl b/media/aidl/android/media/audio/common/Double.aidl new file mode 100644 index 000000000000..d7ab7b8f6431 --- /dev/null +++ b/media/aidl/android/media/audio/common/Double.aidl @@ -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 android.media.audio.common; + +/** + * This is a simple wrapper around a 'double', putting it in a parcelable, so it + * can be used as an 'inout' parameter, be made '@nullable', etc. + * + * {@hide} + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable Double { + double value; +} diff --git a/media/aidl/android/media/audio/common/Float.aidl b/media/aidl/android/media/audio/common/Float.aidl new file mode 100644 index 000000000000..4c5257efa56e --- /dev/null +++ b/media/aidl/android/media/audio/common/Float.aidl @@ -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 android.media.audio.common; + +/** + * This is a simple wrapper around a 'float', putting it in a parcelable, so it + * can be used as an 'inout' parameter, be made '@nullable', etc. + * + * {@hide} + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable Float { + float value; +} diff --git a/media/aidl/android/media/audio/common/Long.aidl b/media/aidl/android/media/audio/common/Long.aidl new file mode 100644 index 000000000000..a4aeb53619c0 --- /dev/null +++ b/media/aidl/android/media/audio/common/Long.aidl @@ -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 android.media.audio.common; + +/** + * This is a simple wrapper around a 'long', putting it in a parcelable, so it + * can be used as an 'inout' parameter, be made '@nullable', etc. + * + * {@hide} + */ +@JavaDerive(equals=true, toString=true) +@VintfStability +parcelable Long { + long value; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Boolean.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Boolean.aidl new file mode 100644 index 000000000000..bc996e441ba3 --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Boolean.aidl @@ -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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +/* @hide */ +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable Boolean { + boolean value; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Byte.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Byte.aidl new file mode 100644 index 000000000000..604e74dbf560 --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Byte.aidl @@ -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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +/* @hide */ +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable Byte { + byte value; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Double.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Double.aidl new file mode 100644 index 000000000000..a525629f2753 --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Double.aidl @@ -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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +/* @hide */ +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable Double { + double value; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Float.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Float.aidl new file mode 100644 index 000000000000..af98eab83dfd --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Float.aidl @@ -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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +/* @hide */ +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable Float { + float value; +} diff --git a/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Long.aidl b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Long.aidl new file mode 100644 index 000000000000..e403dd3fd4ea --- /dev/null +++ b/media/aidl_api/android.media.audio.common.types/current/android/media/audio/common/Long.aidl @@ -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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m <name>-update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.media.audio.common; +/* @hide */ +@JavaDerive(equals=true, toString=true) @VintfStability +parcelable Long { + long value; +} diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index b8e7930e1dca..ad4feecf7d3c 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -335,13 +335,13 @@ final public class MediaMuxer { } /** - * Constructor. * Creates a media muxer that writes to the specified path. + * <p>The caller must not use the file {@code path} before calling {@link #stop}. * @param path The path of the output media file. * @param format The format of the output media file. * @see android.media.MediaMuxer.OutputFormat * @throws IllegalArgumentException if path is invalid or format is not supported. - * @throws IOException if failed to open the file for write. + * @throws IOException if an error occurs while opening or creating the output file. */ public MediaMuxer(@NonNull String path, @Format int format) throws IOException { if (path == null) { @@ -363,16 +363,19 @@ final public class MediaMuxer { } /** - * Constructor. - * Creates a media muxer that writes to the specified FileDescriptor. File descriptor - * must be seekable and writable. Application should not use the file referenced - * by this file descriptor until {@link #stop}. It is the application's responsibility - * to close the file descriptor. It is safe to do so as soon as this call returns. - * @param fd The FileDescriptor of the output media file. + * Creates a media muxer that writes to the specified FileDescriptor. + * <p>The caller must not use the file referenced by the specified {@code fd} before calling + * {@link #stop}. + * <p>It is the caller's responsibility to close the file descriptor, which is safe to do so + * as soon as this call returns. + * @param fd The FileDescriptor of the output media file. If {@code format} is + * {@link OutputFormat#MUXER_OUTPUT_WEBM}, {@code fd} must be open in read-write mode. + * Otherwise, write mode is sufficient, but read-write is also accepted. * @param format The format of the output media file. * @see android.media.MediaMuxer.OutputFormat - * @throws IllegalArgumentException if fd is invalid or format is not supported. - * @throws IOException if failed to open the file for write. + * @throws IllegalArgumentException if {@code format} is not supported, or if {@code fd} is + * not open in the expected mode. + * @throws IOException if an error occurs while performing an IO operation. */ public MediaMuxer(@NonNull FileDescriptor fd, @Format int format) throws IOException { setUpMediaMuxer(fd, format); diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index 267917653efb..b664325ab0d1 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -165,7 +165,11 @@ static jlong android_media_MediaMuxer_native_setup( MediaMuxer::OutputFormat fileFormat = static_cast<MediaMuxer::OutputFormat>(format); - sp<MediaMuxer> muxer = new MediaMuxer(fd, fileFormat); + sp<MediaMuxer> muxer = MediaMuxer::create(fd, fileFormat); + if (muxer == nullptr) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Muxer creation failed"); + return 0; + } muxer->incStrong(clazz); return reinterpret_cast<jlong>(muxer.get()); } diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp index 7acb8c744ba7..a991a71fd3f1 100644 --- a/media/native/midi/Android.bp +++ b/media/native/midi/Android.bp @@ -74,4 +74,8 @@ ndk_library { symbol_file: "libamidi.map.txt", first_version: "29", + export_header_libs: [ + "amidi", + ], + } diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h index fbb7fb329659..2b3170326285 100644 --- a/media/native/midi/include/amidi/AMidi.h +++ b/media/native/midi/include/amidi/AMidi.h @@ -66,7 +66,7 @@ enum { * * Introduced in API 33. */ -enum AMidiDevice_Protocol : int32_t { +typedef enum AMidiDevice_Protocol : int32_t { /** * Constant representing a default protocol with Universal MIDI Packets (UMP). * UMP is defined in "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" spec. @@ -131,7 +131,7 @@ enum AMidiDevice_Protocol : int32_t { * MIDI-CI is defined in "MIDI Capability Inquiry (MIDI-CI)" spec. */ AMIDI_DEVICE_PROTOCOL_UNKNOWN = -1 -}; +} AMidiDevice_Protocol; /* * Device API diff --git a/native/android/Android.bp b/native/android/Android.bp index 32b7a0780e63..8594ba5ca2da 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -27,6 +27,9 @@ ndk_library { symbol_file: "libandroid.map.txt", first_version: "9", unversioned_until: "current", + export_header_libs: [ + "libandroid_headers", + ], } cc_defaults { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java index fe337d267f25..8e33ca338eb1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java @@ -106,13 +106,20 @@ public class LicenseHtmlGeneratorFromXmlTest { + "license content #1\n" + "</pre><!-- license-text -->\n" + "</td></tr><!-- same-license -->\n" - + "</table></body></html>\n"; + + "</table>\n" + + "<div class=\"path-counts\"><table>\n" + + " <tr><th>Path prefix</th><th>Count</th></tr>\n\n" + + " <tr><td>file0</td><td>1</td></tr>\n" + + " <tr><td>file1</td><td>1</td></tr>\n" + + "</table></div>\n\n" + + "</body></html>\n"; private static final String HTML_NEW_BODY_STRING = "<strong>Libraries</strong>\n" + "<ul class=\"libraries\">\n" + "<li><a href=\"#id0\">libA</a></li>\n" + "<li><a href=\"#id1\">libB</a></li>\n" + + "<li><a href=\"#id0\">libC</a></li>\n" + "</ul>\n" + "<strong>Files</strong>\n" + "<ul class=\"files\">\n" @@ -146,7 +153,14 @@ public class LicenseHtmlGeneratorFromXmlTest { + "license content #1\n" + "</pre><!-- license-text -->\n" + "</td></tr><!-- same-license -->\n" - + "</table></body></html>\n"; + + "</table>\n" + + "<div class=\"path-counts\"><table>\n" + + " <tr><th>Path prefix</th><th>Count</th></tr>\n\n" + + " <tr><td>file0</td><td>1</td></tr>\n" + + " <tr><td>file1</td><td>1</td></tr>\n" + + " <tr><td>file2</td><td>1</td></tr>\n" + + "</table></div>\n\n" + + "</body></html>\n"; private static final String EXPECTED_OLD_HTML_STRING = HTML_HEAD_STRING + HTML_OLD_BODY_STRING; @@ -263,7 +277,7 @@ public class LicenseHtmlGeneratorFromXmlTest { Map<String, Set<String>> toOne = new HashMap<>(); toBoth.put("", new HashSet<String>(Arrays.asList("0", "1"))); - toOne.put("", new HashSet<String>(Arrays.asList("0", "1"))); + toOne.put("", new HashSet<String>(Arrays.asList("0"))); fileNameToLibraryToContentIdMap.put("/file0", toBoth); fileNameToLibraryToContentIdMap.put("/file1", toOne); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index b971f7a70ca9..979e9eaa1e84 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -680,6 +680,9 @@ <!-- Permission required for CTS test - Notification test suite --> <uses-permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL" /> + <!-- Permission required for test - CellBroadcastComplianceTest --> + <uses-permission android:name="com.android.cellbroadcastservice.FULL_ACCESS_CELL_BROADCAST_HISTORY" /> + <!-- Permission required for CTS test - CaptioningManagerTest --> <uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" /> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 104998c53e09..0333b2d779df 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -228,7 +228,7 @@ android_library { "metrics-helper-lib", "hamcrest-library", "androidx.test.rules", - "androidx.test.uiautomator", + "androidx.test.uiautomator_uiautomator", "mockito-target-extended-minus-junit4", "testables", "truth-prebuilt", diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index b8a00133c728..1f7021e514e5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.ui import android.annotation.AnyThread import android.annotation.MainThread +import android.app.Activity import android.app.AlertDialog import android.app.Dialog import android.app.PendingIntent @@ -119,8 +120,16 @@ class ControlActionCoordinatorImpl @Inject constructor( } override fun closeDialogs() { - dialog?.dismiss() - dialog = null + val isActivityFinishing = + (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed } + if (isActivityFinishing == true) { + dialog = null + return + } + if (dialog?.isShowing == true) { + dialog?.dismiss() + dialog = null + } } override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 33453a4c31d6..159784575b69 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -631,9 +631,22 @@ public class MediaControlPanel { Drawable artwork; boolean isArtworkBound; Icon artworkIcon = data.getArtwork(); + WallpaperColors wallpaperColors = null; if (artworkIcon != null) { - WallpaperColors wallpaperColors = WallpaperColors - .fromBitmap(artworkIcon.getBitmap()); + if (artworkIcon.getType() == Icon.TYPE_BITMAP + || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { + // Avoids extra processing if this is already a valid bitmap + wallpaperColors = WallpaperColors + .fromBitmap(artworkIcon.getBitmap()); + } else { + Drawable artworkDrawable = artworkIcon.loadDrawable(mContext); + if (artworkDrawable != null) { + wallpaperColors = WallpaperColors + .fromDrawable(artworkIcon.loadDrawable(mContext)); + } + } + } + if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); artwork = getScaledBackground(artworkIcon, width, height); isArtworkBound = true; diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index f2f275323d58..1ab0b5e263d1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -269,6 +269,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { } private void onGroupActionTriggered(boolean isChecked, MediaDevice device) { + disableSeekBar(); if (isChecked && isDeviceIncluded(mController.getSelectableMediaDevice(), device)) { mController.addDeviceToPlayMedia(device); } else if (!isChecked && isDeviceIncluded(mController.getDeselectableMediaDevice(), 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 bec67397a926..3b4ca48046eb 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -273,6 +273,8 @@ public abstract class MediaOutputBaseAdapter extends void initSeekbar(MediaDevice device, boolean isCurrentSeekbarInvisible) { if (!mController.isVolumeControlEnabled(device)) { disableSeekBar(); + } else { + enableSeekBar(); } mSeekBar.setMaxVolume(device.getMaxVolume()); final int currentVolume = device.getCurrentVolume(); @@ -417,11 +419,16 @@ public abstract class MediaOutputBaseAdapter extends return drawable; } - private void disableSeekBar() { + protected void disableSeekBar() { mSeekBar.setEnabled(false); mSeekBar.setOnTouchListener((v, event) -> true); } + private void enableSeekBar() { + mSeekBar.setEnabled(true); + mSeekBar.setOnTouchListener((v, event) -> false); + } + protected void setUpDeviceIcon(MediaDevice device) { ThreadUtils.postOnBackgroundThread(() -> { Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java index 5d7af522176a..6fe06e085556 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java @@ -194,6 +194,11 @@ public class MediaOutputMetricLogger { } private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) { + if (device == null) { + return isSourceDevice + ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE + : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE; + } switch (device.getDeviceType()) { case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE: return isSourceDevice @@ -229,6 +234,9 @@ public class MediaOutputMetricLogger { } private int getInteractionDeviceType(MediaDevice device) { + if (device == null) { + return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE; + } switch (device.getDeviceType()) { case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE: return SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__BUILTIN_SPEAKER; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index fbdabc74aba4..fcd9e10089bc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -19,8 +19,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.Build; -import android.os.Handler; -import android.os.Looper; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Secure; @@ -28,6 +26,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.MainThread; import androidx.annotation.Nullable; import com.android.internal.logging.InstanceId; @@ -35,9 +34,7 @@ import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dumpable; import com.android.systemui.R; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.PluginListener; @@ -68,12 +65,20 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.Executor; import java.util.function.Predicate; import javax.inject.Inject; import javax.inject.Provider; -/** Platform implementation of the quick settings tile host **/ +/** Platform implementation of the quick settings tile host + * + * This class keeps track of the set of current tiles and is the in memory source of truth + * (ground truth is kept in {@link Secure#QS_TILES}). When the ground truth changes, + * {@link #onTuningChanged} will be called and the tiles will be re-created as needed. + * + * This class also provides the interface for adding/removing/changing tiles. + */ @SysUISingleton public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, Dumpable { private static final String TAG = "QSTileHost"; @@ -89,11 +94,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final TunerService mTunerService; private final PluginManager mPluginManager; private final DumpManager mDumpManager; - private final BroadcastDispatcher mBroadcastDispatcher; private final QSLogger mQSLogger; private final UiEventLogger mUiEventLogger; private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; + private final Executor mMainExecutor; private final List<Callback> mCallbacks = new ArrayList<>(); @Nullable @@ -113,13 +118,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D public QSTileHost(Context context, StatusBarIconController iconController, QSFactory defaultFactory, - @Main Handler mainHandler, - @Background Looper bgLooper, + @Main Executor mainExecutor, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, Optional<CentralSurfaces> centralSurfacesOptional, QSLogger qsLogger, UiEventLogger uiEventLogger, @@ -137,7 +140,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mDumpManager = dumpManager; mQSLogger = qsLogger; mUiEventLogger = uiEventLogger; - mBroadcastDispatcher = broadcastDispatcher; + mMainExecutor = mainExecutor; mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this); mTileLifeCycleManagerFactory = tileLifecycleManagerFactory; @@ -151,7 +154,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; - mainHandler.post(() -> { + mainExecutor.execute(() -> { // This is technically a hack to avoid circular dependency of // QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation // finishes before creating any tiles. @@ -258,6 +261,33 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D return mTileSpecs.indexOf(spec); } + /** + * Whenever the Secure Setting keeping track of the current tiles changes (or upon start) this + * will be called with the new value of the setting. + * + * This method will do the following: + * <ol> + * <li>Destroy any existing tile that's not one of the current tiles (in the setting)</li> + * <li>Create new tiles for those that don't already exist. If this tiles end up being + * not available, they'll also be destroyed.</li> + * <li>Save the resolved list of tiles (current tiles that are available) into the setting. + * This means that after this call ends, the tiles in the Setting, {@link #mTileSpecs}, + * and visible tiles ({@link #mTiles}) must match. + * </li> + * </ol> + * + * Additionally, if the user has changed, it'll do the following: + * <ul> + * <li>Change the user for SystemUI tiles: {@link QSTile#userSwitch}.</li> + * <li>Destroy any {@link CustomTile} and recreate it for the new user.</li> + * </ul> + * + * This happens in main thread as {@link com.android.systemui.tuner.TunerServiceImpl} dispatches + * in main thread. + * + * @see QSTile#isAvailable + */ + @MainThread @Override public void onTuningChanged(String key, String newValue) { if (!TILES_SETTING.equals(key)) { @@ -330,34 +360,44 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mCurrentUser = currentUser; List<String> currentSpecs = new ArrayList<>(mTileSpecs); mTileSpecs.clear(); - mTileSpecs.addAll(tileSpecs); + mTileSpecs.addAll(newTiles.keySet()); // Only add the valid (available) tiles. mTiles.clear(); mTiles.putAll(newTiles); if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); - changeTiles(currentSpecs, loadTileSpecs(mContext, "")); + changeTilesByUser(currentSpecs, loadTileSpecs(mContext, "")); } else { + String resolvedTiles = TextUtils.join(",", mTileSpecs); + if (!resolvedTiles.equals(newValue)) { + // If the resolved tiles (those we actually ended up with) are different than + // the ones that are in the setting, update the Setting. + saveTilesToSettings(mTileSpecs); + } for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onTilesChanged(); } } } + /** + * Only use with [CustomTile] if the tile doesn't exist anymore (and therefore doesn't need + * its lifecycle terminated). + */ @Override public void removeTile(String spec) { - changeTileSpecs(tileSpecs-> tileSpecs.remove(spec)); + mMainExecutor.execute(() -> changeTileSpecs(tileSpecs-> tileSpecs.remove(spec))); } /** * Remove many tiles at once. * - * It will only save to settings once (as opposed to {@link QSTileHost#removeTile} called + * It will only save to settings once (as opposed to {@link QSTileHost#removeTileByUser} called * multiple times). */ @Override public void removeTiles(Collection<String> specs) { - changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs)); + mMainExecutor.execute(() -> changeTileSpecs(tileSpecs -> tileSpecs.removeAll(specs))); } @Override @@ -381,27 +421,30 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D * @param requestPosition -1 for end, 0 for beginning, or X for insertion at position X */ public void addTile(String spec, int requestPosition) { - if (spec.equals("work")) Log.wtfStack(TAG, "Adding work tile"); - changeTileSpecs(tileSpecs -> { - if (tileSpecs.contains(spec)) return false; - - int size = tileSpecs.size(); - if (requestPosition == POSITION_AT_END || requestPosition >= size) { - tileSpecs.add(spec); - } else { - tileSpecs.add(requestPosition, spec); - } - return true; - }); + mMainExecutor.execute(() -> + changeTileSpecs(tileSpecs -> { + if (tileSpecs.contains(spec)) return false; + + int size = tileSpecs.size(); + if (requestPosition == POSITION_AT_END || requestPosition >= size) { + tileSpecs.add(spec); + } else { + tileSpecs.add(requestPosition, spec); + } + return true; + }) + ); } - void saveTilesToSettings(List<String> tileSpecs) { - if (tileSpecs.contains("work")) Log.wtfStack(TAG, "Saving work tile"); + + @MainThread + private void saveTilesToSettings(List<String> tileSpecs) { mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs), null /* tag */, false /* default */, mCurrentUser, true /* overrideable by restore */); } + @MainThread private void changeTileSpecs(Predicate<List<String>> changeFunction) { final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser); final List<String> tileSpecs = loadTileSpecs(mContext, setting); @@ -421,29 +464,32 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D */ public void addTile(ComponentName tile, boolean end) { String spec = CustomTile.toSpec(tile); - if (!mTileSpecs.contains(spec)) { - List<String> newSpecs = new ArrayList<>(mTileSpecs); - if (end) { - newSpecs.add(spec); - } else { - newSpecs.add(0, spec); - } - changeTiles(mTileSpecs, newSpecs); - } + addTile(spec, end ? POSITION_AT_END : 0); } - public void removeTile(ComponentName tile) { - List<String> newSpecs = new ArrayList<>(mTileSpecs); - newSpecs.remove(CustomTile.toSpec(tile)); - changeTiles(mTileSpecs, newSpecs); + /** + * This will call through {@link #changeTilesByUser}. It should only be used when a tile is + * removed by a <b>user action</b> like {@code adb}. + */ + public void removeTileByUser(ComponentName tile) { + mMainExecutor.execute(() -> { + List<String> newSpecs = new ArrayList<>(mTileSpecs); + if (newSpecs.remove(CustomTile.toSpec(tile))) { + changeTilesByUser(mTileSpecs, newSpecs); + } + }); } /** * Change the tiles triggered by the user editing. * <p> * This is not called on device start, or on user change. + * + * {@link android.service.quicksettings.TileService#onTileRemoved} will be called for tiles + * that are removed. */ - public void changeTiles(List<String> previousTiles, List<String> newTiles) { + @MainThread + public void changeTilesByUser(List<String> previousTiles, List<String> newTiles) { final List<String> copy = new ArrayList<>(previousTiles); final int NP = copy.size(); for (int i = 0; i < NP; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index e52bfbd67275..d84b12c714bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -182,7 +182,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) { newSpecs.add(mTiles.get(i).spec); } - host.changeTiles(mCurrentSpecs, newSpecs); + host.changeTilesByUser(mCurrentSpecs, newSpecs); mCurrentSpecs = newSpecs; } @@ -200,7 +200,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta /** */ public void resetTileSpecs(List<String> specs) { // Notify the host so the tiles get removed callbacks. - mHost.changeTiles(mCurrentSpecs, specs); + mHost.changeTilesByUser(mCurrentSpecs, specs); setTileSpecs(specs); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index bf565a8c52e0..cfc57db2eeb8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -289,7 +289,7 @@ public class TileServiceManager { } } - mServices.getHost().removeTile(component); + mServices.getHost().removeTile(CustomTile.toSpec(component)); } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 38a208b72edc..f4ca7edb146d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -642,6 +642,8 @@ public class NotificationLockscreenUserManagerImpl implements // - device keyguard is shown in secure mode; // - profile is locked with a work challenge. SparseArray<UserInfo> currentProfiles = getCurrentProfiles(); + SparseBooleanArray oldPublicModes = mLockscreenPublicMode.clone(); + SparseBooleanArray oldWorkChallenges = mUsersWithSeparateWorkChallenge.clone(); mUsersWithSeparateWorkChallenge.clear(); for (int i = currentProfiles.size() - 1; i >= 0; i--) { final int userId = currentProfiles.valueAt(i).id; @@ -660,7 +662,10 @@ public class NotificationLockscreenUserManagerImpl implements } getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode"); // TODO(b/234738798): Migrate KeyguardNotificationVisibilityProvider to use this listener - // notifyNotificationStateChanged(); + if (!mLockscreenPublicMode.equals(oldPublicModes) + || !mUsersWithSeparateWorkChallenge.equals(oldWorkChallenges)) { + notifyNotificationStateChanged(); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt index 6c99e3adb73e..bef3d5095cb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt @@ -20,8 +20,10 @@ import android.service.notification.StatusBarNotification import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.log.LogLevel.WARNING import com.android.systemui.log.dagger.NotificationHeadsUpLog import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.statusbar.notification.collection.NotificationEntry import javax.inject.Inject class NotificationInterruptLogger @Inject constructor( @@ -212,6 +214,33 @@ class NotificationInterruptLogger @Inject constructor( }) } + fun logNoFullscreen(entry: NotificationEntry, reason: String) { + hunBuffer.log(TAG, DEBUG, { + str1 = entry.key + str2 = reason + }, { + "No FullScreenIntent: $str2: $str1" + }) + } + + fun logNoFullscreenWarning(entry: NotificationEntry, reason: String) { + hunBuffer.log(TAG, WARNING, { + str1 = entry.key + str2 = reason + }, { + "No FullScreenIntent: WARNING: $str2: $str1" + }) + } + + fun logFullscreen(entry: NotificationEntry, reason: String) { + hunBuffer.log(TAG, DEBUG, { + str1 = entry.key + str2 = reason + }, { + "FullScreenIntent: $str2: $str1" + }) + } + fun keyguardHideNotification(key: String) { hunBuffer.log(TAG, DEBUG, { str1 = key 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..e1ddbd23e51a 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 @@ -177,9 +177,69 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter */ @Override public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) { - return entry.getSbn().getNotification().fullScreenIntent != null - && (!shouldHeadsUp(entry) - || mStatusBarStateController.getState() == StatusBarState.KEYGUARD); + if (entry.getSbn().getNotification().fullScreenIntent == null) { + return false; + } + + // Never show FSI when suppressed by DND + if (entry.shouldSuppressFullScreenIntent()) { + mLogger.logNoFullscreen(entry, "Suppressed by DND"); + return false; + } + + // Never show FSI if importance is not HIGH + if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) { + mLogger.logNoFullscreen(entry, "Not important enough"); + return false; + } + + // If the notification has suppressive GroupAlertBehavior, block FSI and warn. + StatusBarNotification sbn = entry.getSbn(); + if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) { + // b/231322873: Detect and report an event when a notification has both an FSI and a + // suppressive groupAlertBehavior, and now correctly block the FSI from firing. + final int uid = entry.getSbn().getUid(); + android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "groupAlertBehavior"); + mLogger.logNoFullscreenWarning(entry, "GroupAlertBehavior will prevent HUN"); + return false; + } + + // If the screen is off, then launch the FullScreenIntent + if (!mPowerManager.isInteractive()) { + mLogger.logFullscreen(entry, "Device is not interactive"); + return true; + } + + // If the device is currently dreaming, then launch the FullScreenIntent + if (isDreaming()) { + mLogger.logFullscreen(entry, "Device is dreaming"); + return true; + } + + // If the keyguard is showing, then launch the FullScreenIntent + if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { + mLogger.logFullscreen(entry, "Keyguard is showing"); + return true; + } + + // If the notification should HUN, then we don't need FSI + if (shouldHeadsUp(entry)) { + mLogger.logNoFullscreen(entry, "Expected to HUN"); + return false; + } + + // If the notification won't HUN for some other reason (DND/snooze/etc), launch FSI. + mLogger.logFullscreen(entry, "Expected not to HUN"); + return true; + } + + private boolean isDreaming() { + try { + return mDreamManager.isDreaming(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to query dream manager.", e); + return false; + } } private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) { @@ -219,13 +279,7 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } - boolean isDreaming = false; - try { - isDreaming = mDreamManager.isDreaming(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to query dream manager.", e); - } - boolean inUse = mPowerManager.isScreenOn() && !isDreaming; + boolean inUse = mPowerManager.isScreenOn() && !isDreaming(); if (!inUse) { mLogger.logNoHeadsUpNotInUse(sbn); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 010e6cf90817..e5f8424a2a24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -339,6 +339,13 @@ public class NotificationStackScrollLayoutController { }; /** + * Recalculate sensitiveness without animation; called when waking up while keyguard occluded. + */ + public void updateSensitivenessForOccludedWakeup() { + mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode()); + } + + /** * Set the overexpansion of the panel to be applied to the view. */ public void setOverExpansion(float overExpansion) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index 8782be50794f..9070eadd9944 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -428,7 +428,7 @@ public class AutoTileManager implements UserAwareController { if (isSafetyCenterEnabled && !mAutoTracker.isAdded(mSafetySpec)) { initSafetyTile(); } else if (!isSafetyCenterEnabled && mAutoTracker.isAdded(mSafetySpec)) { - mHost.removeTile(CustomTile.getComponentFromSpec(mSafetySpec)); + mHost.removeTile(mSafetySpec); mHost.unmarkTileAsAutoAdded(mSafetySpec); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 9060d5f67913..ffd50ab5af37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -187,7 +187,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba public void remQsTile(ComponentName tile) { QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); if (qsPanelController != null && qsPanelController.getHost() != null) { - qsPanelController.getHost().removeTile(tile); + qsPanelController.getHost().removeTileByUser(tile); } } 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 7e57dd452cb8..e9a837bc84e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -3384,7 +3384,8 @@ public class CentralSurfacesImpl extends CoreStartable implements // lock screen where users can use the UDFPS affordance to enter the device mStatusBarKeyguardViewManager.reset(true); } else if ((mState == StatusBarState.KEYGUARD - && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) + && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() + && isKeyguardSecure()) || mState == StatusBarState.SHADE_LOCKED) { mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */); } @@ -3687,6 +3688,18 @@ public class CentralSurfacesImpl extends CoreStartable implements public void onFinishedWakingUp() { mWakeUpCoordinator.setFullyAwake(true); mWakeUpCoordinator.setWakingUp(false); + if (mKeyguardStateController.isOccluded() + && !mDozeParameters.canControlUnlockedScreenOff()) { + // When the keyguard is occluded we don't use the KEYGUARD state which would + // normally cause these redaction updates. If AOD is on, the KEYGUARD state is used + // to show the doze, AND UnlockedScreenOffAnimationController.onFinishedWakingUp() + // would force a KEYGUARD state that would take care of recalculating redaction. + // So if AOD is off or unsupported we need to trigger these updates at screen on + // when the keyguard is occluded. + mLockscreenUserManager.updatePublicMode(); + mNotificationPanelViewController.getNotificationStackScrollLayoutController() + .updateSensitivenessForOccludedWakeup(); + } if (mLaunchCameraWhenFinishedWaking) { mNotificationPanelViewController.launchCamera( false /* animate */, mLastCameraLaunchSource); diff --git a/packages/SystemUI/tests/Android.bp b/packages/SystemUI/tests/Android.bp new file mode 100644 index 000000000000..3c418ed49adc --- /dev/null +++ b/packages/SystemUI/tests/Android.bp @@ -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 { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +android_test { + name: "SystemUITests", + + dxflags: ["--multi-dex"], + platform_apis: true, + test_suites: ["device-tests"], + static_libs: ["SystemUI-tests"], + compile_multilib: "both", + + jni_libs: [ + "libdexmakerjvmtiagent", + "libmultiplejvmtiagentsinterferenceagent", + "libstaticjvmtiagent", + ], + libs: [ + "android.test.runner", + "telephony-common", + "android.test.base", + ], + aaptflags: [ + "--extra-packages com.android.systemui", + ], + + // sign this with platform cert, so this test is allowed to inject key events into + // UI it doesn't own. This is necessary to allow screenshots to be taken + certificate: "platform", + + additional_manifests: ["AndroidManifest.xml"], + manifest: "AndroidManifest-base.xml", +} diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk deleted file mode 100644 index ff5165d4e7cf..000000000000 --- a/packages/SystemUI/tests/Android.mk +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_USE_AAPT2 := true -LOCAL_MODULE_TAGS := tests - -LOCAL_JACK_FLAGS := --multi-dex native -LOCAL_DX_FLAGS := --multi-dex - -LOCAL_PACKAGE_NAME := SystemUITests -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_COMPATIBILITY_SUITE := device-tests - -LOCAL_STATIC_ANDROID_LIBRARIES := \ - SystemUI-tests - -LOCAL_MULTILIB := both - -LOCAL_JNI_SHARED_LIBRARIES := \ - libdexmakerjvmtiagent \ - libmultiplejvmtiagentsinterferenceagent \ - libstaticjvmtiagent - -LOCAL_JAVA_LIBRARIES := \ - android.test.runner \ - telephony-common \ - android.test.base \ - -LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui - -# sign this with platform cert, so this test is allowed to inject key events into -# UI it doesn't own. This is necessary to allow screenshots to be taken -LOCAL_CERTIFICATE := platform - -LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest.xml -LOCAL_MANIFEST_FILE := AndroidManifest-base.xml - -# Provide jack a list of classes to exclude from code coverage. -# This is needed because the SystemUITests compile SystemUI source directly, rather than using -# LOCAL_INSTRUMENTATION_FOR := SystemUI. -# -# We want to exclude the test classes from code coverage measurements, but they share the same -# package as the rest of SystemUI so they can't be easily filtered by package name. -# -# Generate a comma separated list of patterns based on the test source files under src/ -# SystemUI classes are in ../src/ so they won't be excluded. -# Example: -# Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java -# Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest* - -# Filter all src files under src/ to just java files -local_java_files := $(filter %.java,$(call all-java-files-under, src)) -# Transform java file names into full class names. -# This only works if the class name matches the file name and the directory structure -# matches the package. -local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files))) -local_comma := , -local_empty := -local_space := $(local_empty) $(local_empty) -# Convert class name list to jacoco exclude list -# This appends a * to all classes and replace the space separators with commas. -jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) - -LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.* -LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) - -ifeq ($(EXCLUDE_SYSTEMUI_TESTS),) - include $(BUILD_PACKAGE) -endif - -# Reset variables -local_java_files := -local_classes := -local_comma := -local_space := -jacoco_exclude := 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..6f4579bb14b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -547,6 +547,19 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun bindAlbumView_artUsesResource() { + val albumArt = Icon.createWithResource(context, R.drawable.ic_android) + val state = mediaData.copy(artwork = albumArt) + + player.attachPlayer(viewHolder) + player.bindPlayer(state, PACKAGE) + bgExecutor.runAllReady() + mainExecutor.runAllReady() + + verify(albumView).setImageDrawable(any(Drawable::class.java)) + } + + @Test fun bindAlbumView_setAfterExecutors() { val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) val canvas = Canvas(bmp) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 59475cf0cb90..c4cb8339c4d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -274,4 +274,30 @@ public class MediaOutputAdapterTest extends SysuiTestCase { verify(mMediaOutputController).connectDevice(mMediaDevice2); } + + @Test + public void onItemClick_onGroupActionTriggered_verifySeekbarDisabled() { + when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(mMediaDevices); + List<MediaDevice> selectableDevices = new ArrayList<>(); + selectableDevices.add(mMediaDevice1); + when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices); + when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(true); + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); + + mViewHolder.mContainerLayout.performClick(); + + assertThat(mViewHolder.mSeekBar.isEnabled()).isFalse(); + } + + @Test + public void onBindViewHolder_volumeControlChangeToEnabled_enableSeekbarAgain() { + when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(false); + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); + assertThat(mViewHolder.mSeekBar.isEnabled()).isFalse(); + + when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true); + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); + + assertThat(mViewHolder.mSeekBar.isEnabled()).isTrue(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 664af75a6529..32c66d25d4aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -32,8 +32,6 @@ import android.app.Fragment; import android.content.Context; import android.graphics.Rect; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; @@ -42,36 +40,23 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; -import com.android.internal.logging.UiEventLogger; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.systemui.R; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.animation.ShadeInterpolation; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.customize.QSCustomizerController; import com.android.systemui.qs.dagger.QSFragmentComponent; -import com.android.systemui.qs.external.CustomTileStatePersister; -import com.android.systemui.qs.external.TileLifecycleManager; import com.android.systemui.qs.external.TileServiceRequestController; -import com.android.systemui.qs.logging.QSLogger; -import com.android.systemui.qs.tileimpl.QSFactoryImpl; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.phone.AutoTileManager; -import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.tuner.TunerService; import com.android.systemui.util.animation.UniqueObjectHostView; -import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; @@ -79,8 +64,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Optional; - @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) @SmallTest @@ -125,34 +108,11 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { mFragments.dispatchResume(); processAllMessages(); - QSTileHost host = - new QSTileHost( - mContext, - mock(StatusBarIconController.class), - mock(QSFactoryImpl.class), - new Handler(), - Looper.myLooper(), - mock(PluginManager.class), - mock(TunerService.class), - () -> mock(AutoTileManager.class), - mock(DumpManager.class), - mock(BroadcastDispatcher.class), - Optional.of(mock(CentralSurfaces.class)), - mock(QSLogger.class), - mock(UiEventLogger.class), - mock(UserTracker.class), - mock(SecureSettings.class), - mock(CustomTileStatePersister.class), - mTileServiceRequestControllerBuilder, - mock(TileLifecycleManager.Factory.class)); - qs.setListening(true); processAllMessages(); qs.setListening(false); processAllMessages(); - host.destroy(); - processAllMessages(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 8cf3fe274848..7dbc561fbfc1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -32,12 +32,11 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; import android.view.View; import androidx.annotation.Nullable; @@ -48,7 +47,6 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.util.CollectionUtils; 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.dump.DumpManager; import com.android.systemui.plugins.ActivityStarter; @@ -68,8 +66,10 @@ import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -81,18 +81,19 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.List; import java.util.Optional; +import java.util.concurrent.Executor; import javax.inject.Provider; @RunWith(AndroidTestingRunner.class) @SmallTest -@RunWithLooper(setAsMainLooper = true) public class QSTileHostTest extends SysuiTestCase { private static String MOCK_STATE_STRING = "MockState"; private static ComponentName CUSTOM_TILE = ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS"); private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE); + private static final String SETTING = QSTileHost.TILES_SETTING; @Mock private StatusBarIconController mIconController; @@ -107,8 +108,6 @@ public class QSTileHostTest extends SysuiTestCase { @Mock private DumpManager mDumpManager; @Mock - private BroadcastDispatcher mBroadcastDispatcher; - @Mock private QSTile.State mMockState; @Mock private CentralSurfaces mCentralSurfaces; @@ -132,31 +131,47 @@ public class QSTileHostTest extends SysuiTestCase { @Mock private TileLifecycleManager mTileLifecycleManager; - private Handler mHandler; - private TestableLooper mLooper; + private FakeExecutor mMainExecutor; + private QSTileHost mQSTileHost; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mLooper = TestableLooper.get(this); - mHandler = new Handler(mLooper.getLooper()); + mMainExecutor = new FakeExecutor(new FakeSystemClock()); + when(mTileServiceRequestControllerBuilder.create(any())) .thenReturn(mTileServiceRequestController); when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class))) .thenReturn(mTileLifecycleManager); mSecureSettings = new FakeSettings(); - mSecureSettings.putStringForUser( - QSTileHost.TILES_SETTING, "", "", false, mUserTracker.getUserId(), false); - mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, - mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, - mBroadcastDispatcher, mCentralSurfaces, mQSLogger, mUiEventLogger, mUserTracker, - mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder, - mTileLifecycleManagerFactory); + saveSetting(""); + mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mMainExecutor, + mPluginManager, mTunerService, mAutoTiles, mDumpManager, mCentralSurfaces, + mQSLogger, mUiEventLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister, + mTileServiceRequestControllerBuilder, mTileLifecycleManagerFactory); + + mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + mMainExecutor.execute(() -> mQSTileHost.onTuningChanged(SETTING, getSetting())); + mMainExecutor.runAllReady(); + } + }, mUserTracker.getUserId()); setUpTileFactory(); } + private void saveSetting(String value) { + mSecureSettings.putStringForUser( + SETTING, value, "", false, mUserTracker.getUserId(), false); + } + + private String getSetting() { + return mSecureSettings.getStringForUser(SETTING, mUserTracker.getUserId()); + } + private void setUpTileFactory() { when(mMockState.toString()).thenReturn(MOCK_STATE_STRING); // Only create this kind of tiles @@ -173,6 +188,10 @@ public class QSTileHostTest extends SysuiTestCase { return new NotAvailableTile(mQSTileHost); } else if (CUSTOM_TILE_SPEC.equals(spec)) { return mCustomTile; + } else if ("internet".equals(spec) + || "wifi".equals(spec) + || "cell".equals(spec)) { + return new TestTile1(mQSTileHost); } else { return null; } @@ -196,14 +215,14 @@ public class QSTileHostTest extends SysuiTestCase { public void testInvalidSpecUsesDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "not-valid"); + saveSetting("not-valid"); assertEquals(2, mQSTileHost.getTiles().size()); } @Test public void testRemoveWifiAndCellularWithoutInternet() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2"); + saveSetting("wifi, spec1, cell, spec2"); assertEquals("internet", mQSTileHost.mTileSpecs.get(0)); assertEquals("spec1", mQSTileHost.mTileSpecs.get(1)); @@ -212,7 +231,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testRemoveWifiAndCellularWithInternet() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet"); + saveSetting("wifi, spec1, cell, spec2, internet"); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); @@ -221,7 +240,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testRemoveWifiWithoutInternet() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2"); + saveSetting("spec1, wifi, spec2"); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); assertEquals("internet", mQSTileHost.mTileSpecs.get(1)); @@ -230,7 +249,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testRemoveCellWithInternet() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet"); + saveSetting("spec1, spec2, cell, internet"); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); @@ -239,7 +258,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testNoWifiNoCellularNoInternet() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + saveSetting("spec1,spec2"); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); @@ -249,7 +268,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testSpecWithInvalidDoesNotUseDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec2,not-valid"); + saveSetting("spec2,not-valid"); assertEquals(1, mQSTileHost.getTiles().size()); QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles()); @@ -258,7 +277,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testDump() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + saveSetting("spec1,spec2"); StringWriter w = new StringWriter(); PrintWriter pw = new PrintWriter(w); mQSTileHost.dump(pw, new String[]{}); @@ -274,7 +293,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "default"); + saveSetting("default"); assertEquals(1, mQSTileHost.getTiles().size()); QSTile element = CollectionUtils.firstOrNull(mQSTileHost.getTiles()); assertTrue(element instanceof TestTile1); @@ -285,7 +304,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testNoRepeatedSpecs_addTile() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + saveSetting("spec1,spec2"); mQSTileHost.addTile("spec1"); @@ -298,9 +317,10 @@ public class QSTileHostTest extends SysuiTestCase { public void testAddTileAtValidPosition() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3"); + saveSetting("spec1,spec3"); mQSTileHost.addTile("spec2", 1); + mMainExecutor.runAllReady(); assertEquals(3, mQSTileHost.mTileSpecs.size()); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); @@ -312,9 +332,10 @@ public class QSTileHostTest extends SysuiTestCase { public void testAddTileAtInvalidPositionAddsToEnd() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3"); + saveSetting("spec1,spec3"); mQSTileHost.addTile("spec2", 100); + mMainExecutor.runAllReady(); assertEquals(3, mQSTileHost.mTileSpecs.size()); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); @@ -326,9 +347,10 @@ public class QSTileHostTest extends SysuiTestCase { public void testAddTileAtEnd() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec3"); - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec3"); + saveSetting("spec1,spec3"); mQSTileHost.addTile("spec2", QSTileHost.POSITION_AT_END); + mMainExecutor.runAllReady(); assertEquals(3, mQSTileHost.mTileSpecs.size()); assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); @@ -338,9 +360,10 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testNoRepeatedSpecs_customTile() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC); + saveSetting(CUSTOM_TILE_SPEC); mQSTileHost.addTile(CUSTOM_TILE, /* end */ false); + mMainExecutor.runAllReady(); assertEquals(1, mQSTileHost.mTileSpecs.size()); assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0)); @@ -348,9 +371,10 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testAddedAtBeginningOnDefault_customTile() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed + saveSetting("spec1"); // seed mQSTileHost.addTile(CUSTOM_TILE); + mMainExecutor.runAllReady(); assertEquals(2, mQSTileHost.mTileSpecs.size()); assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0)); @@ -358,9 +382,10 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testAddedAtBeginning_customTile() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed + saveSetting("spec1"); // seed mQSTileHost.addTile(CUSTOM_TILE, /* end */ false); + mMainExecutor.runAllReady(); assertEquals(2, mQSTileHost.mTileSpecs.size()); assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0)); @@ -368,9 +393,10 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testAddedAtEnd_customTile() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed + saveSetting("spec1"); // seed mQSTileHost.addTile(CUSTOM_TILE, /* end */ true); + mMainExecutor.runAllReady(); assertEquals(2, mQSTileHost.mTileSpecs.size()); assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1)); @@ -409,13 +435,13 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testNotAvailableTile_specNotNull() { - mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "na"); + saveSetting("na"); verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString()); } @Test public void testCustomTileRemoved_stateDeleted() { - mQSTileHost.changeTiles(List.of(CUSTOM_TILE_SPEC), List.of()); + mQSTileHost.changeTilesByUser(List.of(CUSTOM_TILE_SPEC), List.of()); verify(mCustomTileStatePersister) .removeState(new TileServiceKey(CUSTOM_TILE, mQSTileHost.getUserId())); @@ -423,29 +449,99 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testRemoveTiles() { - List<String> tiles = List.of("spec1", "spec2", "spec3"); - mQSTileHost.saveTilesToSettings(tiles); + saveSetting("spec1,spec2,spec3"); mQSTileHost.removeTiles(List.of("spec1", "spec2")); + mMainExecutor.runAllReady(); assertEquals(List.of("spec3"), mQSTileHost.mTileSpecs); } + @Test + public void testTilesRemovedInQuickSuccession() { + saveSetting("spec1,spec2,spec3"); + mQSTileHost.removeTile("spec1"); + mQSTileHost.removeTile("spec3"); + + mMainExecutor.runAllReady(); + assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs); + assertEquals("spec2", getSetting()); + } + + @Test + public void testAddTileInMainThread() { + saveSetting("spec1,spec2"); + + mQSTileHost.addTile("spec3"); + assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs); + + mMainExecutor.runAllReady(); + assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs); + } + + @Test + public void testRemoveTileInMainThread() { + saveSetting("spec1,spec2"); + + mQSTileHost.removeTile("spec1"); + assertEquals(List.of("spec1", "spec2"), mQSTileHost.mTileSpecs); + + mMainExecutor.runAllReady(); + assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs); + } + + @Test + public void testRemoveTilesInMainThread() { + saveSetting("spec1,spec2,spec3"); + + mQSTileHost.removeTiles(List.of("spec3", "spec1")); + assertEquals(List.of("spec1", "spec2", "spec3"), mQSTileHost.mTileSpecs); + + mMainExecutor.runAllReady(); + assertEquals(List.of("spec2"), mQSTileHost.mTileSpecs); + } + + @Test + public void testRemoveTileByUserInMainThread() { + saveSetting("spec1," + CUSTOM_TILE_SPEC); + + mQSTileHost.removeTileByUser(CUSTOM_TILE); + assertEquals(List.of("spec1", CUSTOM_TILE_SPEC), mQSTileHost.mTileSpecs); + + mMainExecutor.runAllReady(); + assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs); + } + + @Test + public void testNonValidTileNotStoredInSettings() { + saveSetting("spec1,not-valid"); + + assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs); + assertEquals("spec1", getSetting()); + } + + @Test + public void testNotAvailableTileNotStoredInSettings() { + saveSetting("spec1,na"); + + assertEquals(List.of("spec1"), mQSTileHost.mTileSpecs); + assertEquals("spec1", getSetting()); + } + private class TestQSTileHost extends QSTileHost { TestQSTileHost(Context context, StatusBarIconController iconController, - QSFactory defaultFactory, Handler mainHandler, Looper bgLooper, + QSFactory defaultFactory, Executor mainExecutor, PluginManager pluginManager, TunerService tunerService, Provider<AutoTileManager> autoTiles, DumpManager dumpManager, - BroadcastDispatcher broadcastDispatcher, CentralSurfaces centralSurfaces, - QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, - SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, + CentralSurfaces centralSurfaces, QSLogger qsLogger, UiEventLogger uiEventLogger, + UserTracker userTracker, SecureSettings secureSettings, + CustomTileStatePersister customTileStatePersister, TileServiceRequestController.Builder tileServiceRequestControllerBuilder, TileLifecycleManager.Factory tileLifecycleManagerFactory) { - super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, - tunerService, autoTiles, dumpManager, broadcastDispatcher, - Optional.of(centralSurfaces), qsLogger, uiEventLogger, userTracker, - secureSettings, customTileStatePersister, tileServiceRequestControllerBuilder, - tileLifecycleManagerFactory); + super(context, iconController, defaultFactory, mainExecutor, pluginManager, + tunerService, autoTiles, dumpManager, Optional.of(centralSurfaces), qsLogger, + uiEventLogger, userTracker, secureSettings, customTileStatePersister, + tileServiceRequestControllerBuilder, tileLifecycleManagerFactory); } @Override @@ -455,25 +551,16 @@ public class QSTileHostTest extends SysuiTestCase { @Override public void onPluginDisconnected(QSFactory plugin) { } - - @Override - void saveTilesToSettings(List<String> tileSpecs) { - super.saveTilesToSettings(tileSpecs); - // After tiles are changed, make sure to call onTuningChanged with the new setting if it - // changed - String specs = mSecureSettings.getStringForUser( - QSTileHost.TILES_SETTING, mUserTracker.getUserId()); - onTuningChanged(TILES_SETTING, specs); - } } + private class TestTile extends QSTileImpl<QSTile.State> { protected TestTile(QSHost host) { super( host, - mLooper.getLooper(), - new Handler(mLooper.getLooper()), + mock(Looper.class), + mock(Handler.class), new FalsingManagerFake(), mock(MetricsLogger.class), mock(StatusBarStateController.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java index 3d53062d7d02..d42cbe3b698a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java @@ -55,6 +55,6 @@ public class TileAdapterTest extends SysuiTestCase { @Test public void testResetNotifiesHost() { mTileAdapter.resetTileSpecs(Collections.emptyList()); - verify(mQSTileHost).changeTiles(any(), any()); + verify(mQSTileHost).changeTilesByUser(any(), any()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 6b7e5b9335f2..471ddfd3f224 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Intent; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.RemoteException; import android.os.UserHandle; import android.service.quicksettings.IQSTileService; @@ -65,6 +66,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Optional; +import java.util.concurrent.Executor; import javax.inject.Provider; @@ -130,17 +132,16 @@ public class TileServicesTest extends SysuiTestCase { .thenReturn(mTileLifecycleManager); Provider<Handler> provider = () -> new Handler(mTestableLooper.getLooper()); + Executor executor = new HandlerExecutor(provider.get()); QSTileHost host = new QSTileHost(mContext, mStatusBarIconController, mQSFactory, - provider.get(), - mTestableLooper.getLooper(), + executor, mPluginManager, mTunerService, () -> mAutoTileManager, mDumpManager, - mock(BroadcastDispatcher.class), Optional.of(mCentralSurfaces), mQSLogger, mUiEventLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 7687d1204541..dd2b66765fae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -29,7 +29,9 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,6 +61,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor; +import com.android.systemui.statusbar.NotificationLockscreenUserManager.NotificationStateChangedListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -325,6 +328,38 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { } @Test + public void testUpdateIsPublicMode() { + when(mKeyguardStateController.isMethodSecure()).thenReturn(true); + + NotificationStateChangedListener listener = mock(NotificationStateChangedListener.class); + mLockscreenUserManager.addNotificationStateChangedListener(listener); + mLockscreenUserManager.mCurrentProfiles.append(0, mock(UserInfo.class)); + + // first call explicitly sets user 0 to not public; notifies + mLockscreenUserManager.updatePublicMode(); + assertFalse(mLockscreenUserManager.isLockscreenPublicMode(0)); + verify(listener).onNotificationStateChanged(); + clearInvocations(listener); + + // calling again has no changes; does not notify + mLockscreenUserManager.updatePublicMode(); + assertFalse(mLockscreenUserManager.isLockscreenPublicMode(0)); + verify(listener, never()).onNotificationStateChanged(); + + // Calling again with keyguard now showing makes user 0 public; notifies + when(mKeyguardStateController.isShowing()).thenReturn(true); + mLockscreenUserManager.updatePublicMode(); + assertTrue(mLockscreenUserManager.isLockscreenPublicMode(0)); + verify(listener).onNotificationStateChanged(); + clearInvocations(listener); + + // calling again has no changes; does not notify + mLockscreenUserManager.updatePublicMode(); + assertTrue(mLockscreenUserManager.isLockscreenPublicMode(0)); + verify(listener, never()).onNotificationStateChanged(); + } + + @Test public void testShowSilentNotifications_settingSaysShow() { mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1); mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1); 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 90627cb0fa78..25add0da4e71 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 @@ -24,6 +24,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; +import static com.android.systemui.statusbar.StatusBarState.KEYGUARD; import static com.android.systemui.statusbar.StatusBarState.SHADE; import static com.google.common.truth.Truth.assertThat; @@ -31,6 +32,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.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; @@ -95,6 +97,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { NotifPipelineFlags mFlags; @Mock KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider; + @Mock + PendingIntent mPendingIntent; private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider; @@ -422,6 +426,122 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } + @Test + public void testShouldNotFullScreen_notPendingIntent() throws RemoteException { + NotificationEntry entry = createNotification(IMPORTANCE_HIGH); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isFalse(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldNotFullScreen_notHighImportance() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_DEFAULT, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isFalse(); + verify(mLogger).logNoFullscreen(entry, "Not important enough"); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldNotFullScreen_isGroupAlertSilenced() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ true); + when(mPowerManager.isInteractive()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(true); + when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isFalse(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger).logNoFullscreenWarning(entry, "GroupAlertBehavior will prevent HUN"); + verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldFullScreen_notInteractive() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(false); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isTrue(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger).logFullscreen(entry, "Device is not interactive"); + } + + @Test + public void testShouldFullScreen_isDreaming() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(true); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isTrue(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger).logFullscreen(entry, "Device is dreaming"); + } + + @Test + public void testShouldFullScreen_onKeyguard() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(KEYGUARD); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isTrue(); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger).logFullscreen(entry, "Keyguard is showing"); + } + + @Test + public void testShouldNotFullScreen_willHun() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mPowerManager.isScreenOn()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isFalse(); + verify(mLogger).logNoFullscreen(entry, "Expected to HUN"); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger, never()).logFullscreen(any(), any()); + } + + @Test + public void testShouldFullScreen_packageSnoozed() throws RemoteException { + NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false); + when(mPowerManager.isInteractive()).thenReturn(true); + when(mPowerManager.isScreenOn()).thenReturn(true); + when(mDreamManager.isDreaming()).thenReturn(false); + when(mStatusBarStateController.getState()).thenReturn(SHADE); + when(mHeadsUpManager.isSnoozed("a")).thenReturn(true); + + assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .isTrue(); + verify(mLogger).logNoHeadsUpPackageSnoozed(entry.getSbn()); + verify(mLogger, never()).logNoFullscreen(any(), any()); + verify(mLogger, never()).logNoFullscreenWarning(any(), any()); + verify(mLogger).logFullscreen(entry, "Expected not to HUN"); + } + /** * Bubbles can happen. */ @@ -526,6 +646,10 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { .setContentText("content text") .build(); + return createNotification(importance, n); + } + + private NotificationEntry createNotification(int importance, Notification n) { return new NotificationEntryBuilder() .setPkg("a") .setOpPkg("a") @@ -536,6 +660,20 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { .build(); } + private NotificationEntry createFsiNotification(int importance, boolean silent) { + Notification n = new Notification.Builder(getContext(), "a") + .setContentTitle("title") + .setContentText("content text") + .setFullScreenIntent(mPendingIntent, true) + .setGroup("fsi") + .setGroupAlertBehavior(silent + ? Notification.GROUP_ALERT_SUMMARY + : Notification.GROUP_ALERT_ALL) + .build(); + + return createNotification(importance, n); + } + private final NotificationInterruptSuppressor mSuppressAwakeHeadsUp = new NotificationInterruptSuppressor() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java index 371119cc6d01..4ccbc6d45e63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java @@ -490,7 +490,7 @@ public class AutoTileManagerTest extends SysuiTestCase { mAutoTileManager.init(); when(mAutoAddTracker.isAdded(TEST_CUSTOM_SAFETY_SPEC)).thenReturn(true); mAutoTileManager.mSafetyCallback.onSafetyCenterEnableChanged(false); - verify(mQsTileHost, times(1)).removeTile(safetyComponent); + verify(mQsTileHost, times(1)).removeTile(TEST_CUSTOM_SAFETY_SPEC); } @Test diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS index 2b9f179b832d..6e76a207e06f 100644 --- a/services/accessibility/OWNERS +++ b/services/accessibility/OWNERS @@ -2,3 +2,5 @@ pweaver@google.com sallyyuen@google.com ryanlwlin@google.com fuego@google.com +danielnorman@google.com +aarmaly@google.com diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 9b29bae1fc46..9e428877d9dc 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -176,6 +176,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private boolean mSendMotionEvents; + private SparseArray<Boolean> mServiceDetectsGestures = new SparseArray<>(0); boolean mRequestFilterKeyEvents; boolean mRetrieveInteractiveWindows; @@ -2344,9 +2345,17 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) { + mServiceDetectsGestures.put(displayId, mode); mSystemSupport.setServiceDetectsGesturesEnabled(displayId, mode); } + public boolean isServiceDetectsGesturesEnabled(int displayId) { + if (mServiceDetectsGestures.contains(displayId)) { + return mServiceDetectsGestures.get(displayId); + } + return false; + } + public void requestTouchExploration(int displayId) { mSystemSupport.requestTouchExploration(displayId); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 75724bffabf8..952e85a310bc 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -176,6 +176,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private int mEnabledFeatures; + // Display-specific features + private SparseArray<Boolean> mServiceDetectsGestures = new SparseArray<>(); private final SparseArray<EventStreamState> mMouseStreamStates = new SparseArray<>(0); private final SparseArray<EventStreamState> mTouchScreenStreamStates = new SparseArray<>(0); @@ -458,7 +460,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo final Context displayContext = mContext.createDisplayContext(display); final int displayId = display.getDisplayId(); - + if (!mServiceDetectsGestures.contains(displayId)) { + mServiceDetectsGestures.put(displayId, false); + } if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { if (mAutoclickController == null) { mAutoclickController = new AutoclickController( @@ -481,6 +485,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_SEND_MOTION_EVENTS) != 0) { explorer.setSendMotionEventsEnabled(true); } + explorer.setServiceDetectsGestures(mServiceDetectsGestures.get(displayId)); addFirstEventHandler(displayId, explorer); mTouchExplorer.put(displayId, explorer); } @@ -565,7 +570,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mTouchExplorer.remove(displayId); } - final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId); + final MagnificationGestureHandler handler = + mMagnificationGestureHandler.get(displayId); if (handler != null) { handler.onDestroy(); mMagnificationGestureHandler.remove(displayId); @@ -897,8 +903,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if (mTouchExplorer.contains(displayId)) { mTouchExplorer.get(displayId).setServiceDetectsGestures(mode); } + mServiceDetectsGestures.put(displayId, mode); } + public void resetServiceDetectsGestures() { + mServiceDetectsGestures.clear(); + } public void requestTouchExploration(int displayId) { if (mTouchExplorer.contains(displayId)) { mTouchExplorer.get(displayId).requestTouchExploration(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 9a1d29554ad6..cdfa0c0411e4 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -728,7 +728,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); intentFilter.addAction(Intent.ACTION_USER_REMOVED); - intentFilter.addAction(Intent.ACTION_USER_PRESENT); intentFilter.addAction(Intent.ACTION_SETTING_RESTORED); mContext.registerReceiverAsUser(new BroadcastReceiver() { @@ -746,14 +745,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); } else if (Intent.ACTION_USER_REMOVED.equals(action)) { removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } else if (Intent.ACTION_USER_PRESENT.equals(action)) { - // We will update when the automation service dies. - synchronized (mLock) { - AccessibilityUserState userState = getCurrentUserStateLocked(); - if (readConfigurationForUserStateLocked(userState)) { - onUserStateChangedLocked(userState); - } - } } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) { @@ -1730,31 +1721,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private boolean scheduleNotifyMotionEvent(MotionEvent event) { + boolean result = false; + int displayId = event.getDisplayId(); synchronized (mLock) { AccessibilityUserState state = getCurrentUserStateLocked(); for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { AccessibilityServiceConnection service = state.mBoundServices.get(i); - if (service.mRequestTouchExplorationMode) { + if (service.isServiceDetectsGesturesEnabled(displayId)) { service.notifyMotionEvent(event); - return true; + result = true; } } } - return false; + return result; } private boolean scheduleNotifyTouchState(int displayId, int touchState) { + boolean result = false; synchronized (mLock) { AccessibilityUserState state = getCurrentUserStateLocked(); for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { AccessibilityServiceConnection service = state.mBoundServices.get(i); - if (service.mRequestTouchExplorationMode) { + if (service.isServiceDetectsGesturesEnabled(displayId)) { service.notifyTouchState(displayId, touchState); - return true; + result = true; } } } - return false; + return result; } private void notifyClearAccessibilityCacheLocked() { @@ -2323,12 +2317,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isPerformGesturesEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS; } + if (flags != 0) { if (!mHasInputFilter) { mHasInputFilter = true; if (mInputFilter == null) { - mInputFilter = new AccessibilityInputFilter(mContext, - AccessibilityManagerService.this); + mInputFilter = + new AccessibilityInputFilter( + mContext, AccessibilityManagerService.this); } inputFilter = mInputFilter; setInputFilter = true; @@ -2338,6 +2334,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mHasInputFilter) { mHasInputFilter = false; mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0); + mInputFilter.resetServiceDetectsGestures(); + if (userState.isTouchExplorationEnabledLocked()) { + // Service gesture detection is turned on and off on a per-display + // basis. + final ArrayList<Display> displays = getValidDisplayList(); + for (Display display : displays) { + int displayId = display.getDisplayId(); + boolean mode = userState.isServiceDetectsGesturesEnabled(displayId); + mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode); + } + } inputFilter = null; setInputFilter = true; } @@ -2653,6 +2660,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub Binder.restoreCallingIdentity(identity); } } + // Service gesture detection is turned on and off on a per-display + // basis. + userState.resetServiceDetectsGestures(); + final ArrayList<Display> displays = getValidDisplayList(); + for (AccessibilityServiceConnection service: userState.mBoundServices) { + for (Display display : displays) { + int displayId = display.getDisplayId(); + if (service.isServiceDetectsGesturesEnabled(displayId)) { + userState.setServiceDetectsGesturesEnabled(displayId, true); + } + } + } userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); @@ -4313,6 +4332,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private void setServiceDetectsGesturesInternal(int displayId, boolean mode) { synchronized (mLock) { + getCurrentUserStateLocked().setServiceDetectsGesturesEnabled(displayId, mode); if (mHasInputFilter && mInputFilter != null) { mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 55dc196fc18d..a0fc8d30f64c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -44,6 +44,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseIntArray; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManagerClient; @@ -118,6 +119,7 @@ class AccessibilityUserState { private boolean mRequestMultiFingerGestures; private boolean mRequestTwoFingerPassthrough; private boolean mSendMotionEventsEnabled; + private SparseArray<Boolean> mServiceDetectsGestures = new SparseArray<>(0); private int mUserInteractiveUiTimeout; private int mUserNonInteractiveUiTimeout; private int mNonInteractiveUiTimeout = 0; @@ -987,4 +989,18 @@ class AccessibilityUserState { mFocusStrokeWidth = strokeWidth; mFocusColor = color; } + + public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) { + mServiceDetectsGestures.put(displayId, mode); + } + + public void resetServiceDetectsGestures() { + mServiceDetectsGestures.clear(); + } + public boolean isServiceDetectsGesturesEnabled(int displayId) { + if (mServiceDetectsGestures.contains(displayId)) { + return mServiceDetectsGestures.get(displayId); + } + return false; + } } diff --git a/services/companion/java/com/android/server/companion/virtual/OWNERS b/services/companion/java/com/android/server/companion/virtual/OWNERS index b3c3a4d3a192..5e8291fe5587 100644 --- a/services/companion/java/com/android/server/companion/virtual/OWNERS +++ b/services/companion/java/com/android/server/companion/virtual/OWNERS @@ -2,3 +2,4 @@ set noparent ogunwale@google.com michaelwr@google.com +vladokom@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index 2015dc929a59..804d7f3b7d60 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -165,9 +165,14 @@ public class NetworkTimeUpdateService extends Binder { mContext.enforceCallingPermission( android.Manifest.permission.SET_TIME, "clear latest network time"); - mTime.clearCachedTimeResult(); + final long token = Binder.clearCallingIdentity(); + try { + mTime.clearCachedTimeResult(); - mLocalLog.log("clearTimeForTests"); + mLocalLog.log("clearTimeForTests"); + } finally { + Binder.restoreCallingIdentity(token); + } } /** @@ -181,15 +186,19 @@ public class NetworkTimeUpdateService extends Binder { mContext.enforceCallingPermission( android.Manifest.permission.SET_TIME, "force network time refresh"); - boolean success = mTime.forceRefresh(); - mLocalLog.log("forceRefreshForTests: success=" + success); + final long token = Binder.clearCallingIdentity(); + try { + boolean success = mTime.forceRefresh(); + mLocalLog.log("forceRefreshForTests: success=" + success); - if (success) { - makeNetworkTimeSuggestion(mTime.getCachedTimeResult(), - "Origin: NetworkTimeUpdateService: forceRefreshForTests"); + if (success) { + makeNetworkTimeSuggestion(mTime.getCachedTimeResult(), + "Origin: NetworkTimeUpdateService: forceRefreshForTests"); + } + return success; + } finally { + Binder.restoreCallingIdentity(token); } - - return success; } /** @@ -201,10 +210,15 @@ public class NetworkTimeUpdateService extends Binder { mContext.enforceCallingPermission( android.Manifest.permission.SET_TIME, "set NTP server config for tests"); - mLocalLog.log("Setting server config for tests: hostname=" + hostname - + ", port=" + port - + ", timeout=" + timeout); - mTime.setServerConfigForTests(hostname, port, timeout); + final long token = Binder.clearCallingIdentity(); + try { + mLocalLog.log("Setting server config for tests: hostname=" + hostname + + ", port=" + port + + ", timeout=" + timeout); + mTime.setServerConfigForTests(hostname, port, timeout); + } finally { + Binder.restoreCallingIdentity(token); + } } private void onPollNetworkTime(int event) { diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 6ff8e36a1f82..c4418592226d 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -16,6 +16,7 @@ per-file ServiceWatcher.java = sooniln@google.com # Health per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OWNERS +per-file *Accessibility* = file:/services/accessibility/OWNERS per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Battery* = file:/BATTERY_STATS_OWNERS @@ -35,6 +36,8 @@ per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWN per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS per-file PinnerService.java = file:/apct-tests/perftests/OWNERS per-file RescueParty.java = fdunlap@google.com, shuc@google.com +per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS +per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS per-file TelephonyRegistry.java = file:/telephony/OWNERS per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index b86fe7ec4c32..f7b05f2b895a 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -373,7 +373,7 @@ class StorageManagerService extends IStorageManager.Stub private volatile boolean mChargingRequired; private volatile int mMinGCSleepTime; private volatile int mTargetDirtyRatio; - private volatile boolean mNeedGC; + private volatile boolean mNeedGC = true; private volatile boolean mPassedLifetimeThresh; // Tracking storage write amounts in one period diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 7d8c19f41ae4..6b731c319c4b 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -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/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index 6076eb1f69ee..7a09ce722f94 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -2790,13 +2790,6 @@ public final class AppRestrictionController { if (isOnSystemDeviceIdleAllowlist(uid)) { return REASON_SYSTEM_ALLOW_LISTED; } - if (isOnDeviceIdleAllowlist(uid)) { - return REASON_ALLOWLISTED_PACKAGE; - } - final ActivityManagerInternal am = mInjector.getActivityManagerInternal(); - if (am.isAssociatedCompanionApp(UserHandle.getUserId(uid), uid)) { - return REASON_COMPANION_DEVICE_MANAGER; - } if (UserManager.isDeviceInDemoMode(mContext)) { return REASON_DEVICE_DEMO_MODE; } @@ -2805,6 +2798,7 @@ public final class AppRestrictionController { .hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)) { return REASON_DISALLOW_APPS_CONTROL; } + final ActivityManagerInternal am = mInjector.getActivityManagerInternal(); if (am.isDeviceOwner(uid)) { return REASON_DEVICE_OWNER; } @@ -2822,14 +2816,9 @@ public final class AppRestrictionController { final AppOpsManager appOpsManager = mInjector.getAppOpsManager(); final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); + // Check each packages to see if any of them is in the "fixed" exemption cases. for (String pkg : packages) { - if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, - uid, pkg) == AppOpsManager.MODE_ALLOWED) { - return REASON_OP_ACTIVATE_VPN; - } else if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, - uid, pkg) == AppOpsManager.MODE_ALLOWED) { - return REASON_OP_ACTIVATE_PLATFORM_VPN; - } else if (isSystemModule(pkg)) { + if (isSystemModule(pkg)) { return REASON_SYSTEM_MODULE; } else if (isCarrierApp(pkg)) { return REASON_CARRIER_PRIVILEGED_APP; @@ -2843,6 +2832,16 @@ public final class AppRestrictionController { return REASON_ACTIVE_DEVICE_ADMIN; } } + // Loop the packages again, and check the user-configurable exemptions. + for (String pkg : packages) { + if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, + uid, pkg) == AppOpsManager.MODE_ALLOWED) { + return REASON_OP_ACTIVATE_VPN; + } else if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, + uid, pkg) == AppOpsManager.MODE_ALLOWED) { + return REASON_OP_ACTIVATE_PLATFORM_VPN; + } + } } if (isRoleHeldByUid(RoleManager.ROLE_DIALER, uid)) { return REASON_ROLE_DIALER; @@ -2850,6 +2849,12 @@ public final class AppRestrictionController { if (isRoleHeldByUid(RoleManager.ROLE_EMERGENCY, uid)) { return REASON_ROLE_EMERGENCY; } + if (isOnDeviceIdleAllowlist(uid)) { + return REASON_ALLOWLISTED_PACKAGE; + } + if (am.isAssociatedCompanionApp(UserHandle.getUserId(uid), uid)) { + return REASON_COMPANION_DEVICE_MANAGER; + } return REASON_DENIED; } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 178b6bbe755e..eb6a3b3a3cea 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -27,6 +27,7 @@ import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; +import static android.os.Process.getAdvertisedMem; import static android.os.Process.getFreeMemory; import static android.os.Process.getTotalMemory; import static android.os.Process.killProcessQuiet; @@ -1524,6 +1525,7 @@ public final class ProcessList { void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { final long homeAppMem = getMemLevel(HOME_APP_ADJ); final long cachedAppMem = getMemLevel(CACHED_APP_MIN_ADJ); + outInfo.advertisedMem = getAdvertisedMem(); outInfo.availMem = getFreeMemory(); outInfo.totalMem = getTotalMemory(); outInfo.threshold = homeAppMem; diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java index cee34d5568b5..252a00bace20 100644 --- a/services/core/java/com/android/server/am/ProcessProfileRecord.java +++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java @@ -17,7 +17,6 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; -import static android.app.ActivityManager.processStateAmToProto; import android.annotation.IntDef; import android.app.IApplicationThread; @@ -318,12 +317,6 @@ final class ProcessProfileRecord { origBase.setState(ProcessStats.STATE_NOTHING, tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.getPackageListLocked()); - pkgList.forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - mApp.uid, mApp.processName, pkgName, - processStateAmToProto(ProcessStats.STATE_NOTHING), - holder.appVersion) - ); } origBase.makeInactive(); } @@ -362,12 +355,6 @@ final class ProcessProfileRecord { origBase.setState(ProcessStats.STATE_NOTHING, tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.getPackageListLocked()); - pkgList.forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - mApp.uid, mApp.processName, pkgName, - processStateAmToProto(ProcessStats.STATE_NOTHING), - holder.appVersion) - ); } origBase.makeInactive(); setBaseProcessTracker(null); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 07b6fcdcb0ca..482e6a792a90 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -54,7 +54,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.procstats.ProcessState; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.Zygote; -import com.android.internal.util.FrameworkStatsLog; import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; @@ -1212,12 +1211,6 @@ class ProcessRecord implements WindowProcessListener { long now = SystemClock.uptimeMillis(); baseProcessTracker.setState(ProcessStats.STATE_NOTHING, tracker.getMemFactorLocked(), now, mPkgList.getPackageListLocked()); - mPkgList.forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgName, - ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), - holder.appVersion) - ); if (numOfPkgs != 1) { mPkgList.forEachPackageProcessStats(holder -> { if (holder.state != null && holder.state != baseProcessTracker) { diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index 262436d693ec..f0241aa5ed82 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -36,7 +36,6 @@ import android.util.TimeUtils; import com.android.internal.annotations.CompositeRWLock; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.FrameworkStatsLog; import com.android.server.am.PlatformCompatCache.CachedCompatChangeId; import java.io.PrintWriter; @@ -599,12 +598,6 @@ final class ProcessStateRecord { @GuardedBy({"mService", "mProcLock"}) void setReportedProcState(int repProcState) { mRepProcState = repProcState; - mApp.getPkgList().forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - mApp.uid, mApp.processName, pkgName, - ActivityManager.processStateAmToProto(mRepProcState), - holder.appVersion) - ); mApp.getWindowProcessController().setReportedProcState(repProcState); } @@ -620,12 +613,6 @@ final class ProcessStateRecord { mRepProcState = newState; setCurProcState(newState); setCurRawProcState(newState); - mApp.getPkgList().forEachPackage((pkgName, holder) -> - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - mApp.uid, mApp.processName, pkgName, - ActivityManager.processStateAmToProto(mRepProcState), - holder.appVersion) - ); } } } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 5b80f40aa2c0..5ddb45ded19e 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -90,6 +90,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_NETD_NATIVE, DeviceConfig.NAMESPACE_NNAPI_NATIVE, DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, + DeviceConfig.NAMESPACE_REMOTE_KEY_PROVISIONING_NATIVE, DeviceConfig.NAMESPACE_RUNTIME_NATIVE, DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, DeviceConfig.NAMESPACE_STATSD_NATIVE, diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index eba9c7a5f14e..8e179b942d1e 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -17,9 +17,12 @@ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.compat.CompatChanges; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -118,8 +121,39 @@ import java.util.concurrent.atomic.AtomicBoolean; // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 /*package*/ final Object mSetModeLock = new Object(); - /** PID of current audio mode owner communicated by AudioService */ - private int mModeOwnerPid = 0; + /** AudioModeInfo contains information on current audio mode owner + * communicated by AudioService */ + /* package */ static final class AudioModeInfo { + /** Current audio mode */ + final int mMode; + /** PID of current audio mode owner */ + final int mPid; + /** UID of current audio mode owner */ + final int mUid; + + AudioModeInfo(int mode, int pid, int uid) { + mMode = mode; + mPid = pid; + mUid = uid; + } + + @Override + public String toString() { + return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode) + + ", mPid=" + mPid + + ", mUid=" + mUid; + } + }; + + private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0); + + /** + * Indicates that default communication device is chosen by routing rules in audio policy + * manager and not forced by AudioDeviceBroker. + */ + @ChangeId + @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) + public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L; //------------------------------------------------------------------- /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { @@ -187,7 +221,7 @@ import java.util.concurrent.atomic.AtomicBoolean; /*package*/ void onSystemReady() { synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - mModeOwnerPid = mAudioService.getModeOwnerPid(); + mAudioModeOwner = mAudioService.getAudioModeOwner(); mBtHelper.onSystemReady(); } } @@ -368,11 +402,11 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") private CommunicationRouteClient topCommunicationRouteClient() { for (CommunicationRouteClient crc : mCommunicationRouteClients) { - if (crc.getPid() == mModeOwnerPid) { + if (crc.getPid() == mAudioModeOwner.mPid) { return crc; } } - if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) { + if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) { return mCommunicationRouteClients.get(0); } return null; @@ -390,7 +424,7 @@ import java.util.concurrent.atomic.AtomicBoolean; AudioDeviceAttributes device = crc != null ? crc.getDevice() : null; if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "requestedCommunicationDevice, device: " - + device + " mode owner pid: " + mModeOwnerPid); + + device + " mAudioModeOwner: " + mAudioModeOwner.toString()); } return device; } @@ -774,8 +808,9 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info); } - /*package*/ void postSetModeOwnerPid(int pid, int mode) { - sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode); + /*package*/ void postSetModeOwner(int mode, int pid, int uid) { + sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE, + new AudioModeInfo(mode, pid, uid)); } /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { @@ -1162,7 +1197,7 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println(prefix + "mAccessibilityStrategyId: " + mAccessibilityStrategyId); - pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid); + pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner); mBtHelper.dump(pw, prefix); } @@ -1288,12 +1323,19 @@ import java.util.concurrent.atomic.AtomicBoolean; } break; case MSG_L_SET_BT_ACTIVE_DEVICE: - synchronized (mDeviceStateLock) { - BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; - mDeviceInventory.onSetBtActiveDevice(btInfo, - (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput) - ? mAudioService.getBluetoothContextualVolumeStream() - : AudioSystem.STREAM_DEFAULT); + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; + mDeviceInventory.onSetBtActiveDevice(btInfo, + (btInfo.mProfile + != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput) + ? mAudioService.getBluetoothContextualVolumeStream() + : AudioSystem.STREAM_DEFAULT); + if (btInfo.mProfile == BluetoothProfile.LE_AUDIO + || btInfo.mProfile == BluetoothProfile.HEARING_AID) { + onUpdateCommunicationRouteClient("setBluetoothActiveDevice"); + } + } } break; case MSG_BT_HEADSET_CNCT_FAILED: @@ -1338,11 +1380,11 @@ import java.util.concurrent.atomic.AtomicBoolean; mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); } break; - case MSG_I_SET_MODE_OWNER_PID: + case MSG_I_SET_MODE_OWNER: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - mModeOwnerPid = msg.arg1; - if (msg.arg2 != AudioSystem.MODE_RINGTONE) { + mAudioModeOwner = (AudioModeInfo) msg.obj; + if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) { onUpdateCommunicationRouteClient("setNewModeOwner"); } } @@ -1504,7 +1546,7 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_REPORT_NEW_ROUTES = 13; private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; - private static final int MSG_I_SET_MODE_OWNER_PID = 16; + private static final int MSG_I_SET_MODE_OWNER = 16; private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22; private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23; @@ -1826,8 +1868,16 @@ import java.util.concurrent.atomic.AtomicBoolean; AudioSystem.setParameters("BT_SCO=on"); } if (preferredCommunicationDevice == null) { - removePreferredDevicesForStrategySync(mCommunicationStrategyId); - removePreferredDevicesForStrategySync(mAccessibilityStrategyId); + AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice(); + if (defaultDevice != null) { + setPreferredDevicesForStrategySync( + mCommunicationStrategyId, Arrays.asList(defaultDevice)); + setPreferredDevicesForStrategySync( + mAccessibilityStrategyId, Arrays.asList(defaultDevice)); + } else { + removePreferredDevicesForStrategySync(mCommunicationStrategyId); + removePreferredDevicesForStrategySync(mAccessibilityStrategyId); + } } else { setPreferredDevicesForStrategySync( mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); @@ -1856,26 +1906,24 @@ import java.util.concurrent.atomic.AtomicBoolean; } } + // @GuardedBy("mSetModeLock") + @GuardedBy("mDeviceStateLock") private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { - synchronized (mSetModeLock) { - synchronized (mDeviceStateLock) { - boolean wasSpeakerphoneActive = isSpeakerphoneActive(); - mPreferredCommunicationDevice = device; - updateActiveCommunicationDevice(); - if (wasSpeakerphoneActive != isSpeakerphoneActive()) { - try { - mContext.sendBroadcastAsUser( - new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) - .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), - UserHandle.ALL); - } catch (Exception e) { - Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); - } - } - mAudioService.postUpdateRingerModeServiceInt(); - dispatchCommunicationDevice(); + boolean wasSpeakerphoneActive = isSpeakerphoneActive(); + mPreferredCommunicationDevice = device; + updateActiveCommunicationDevice(); + if (wasSpeakerphoneActive != isSpeakerphoneActive()) { + try { + mContext.sendBroadcastAsUser( + new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), + UserHandle.ALL); + } catch (Exception e) { + Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); } } + mAudioService.postUpdateRingerModeServiceInt(); + dispatchCommunicationDevice(); } private CommunicationRouteClient removeCommunicationRouteClient( @@ -1915,6 +1963,32 @@ import java.util.concurrent.atomic.AtomicBoolean; return null; } + @GuardedBy("mDeviceStateLock") + private boolean communnicationDeviceCompatOn() { + return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION + && !(CompatChanges.isChangeEnabled( + USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid) + || mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID); + } + + @GuardedBy("mDeviceStateLock") + AudioDeviceAttributes getDefaultCommunicationDevice() { + // For system server (Telecom) and APKs targeting S and above, we let the audio + // policy routing rules select the default communication device. + // For older APKs, we force Hearing Aid or LE Audio headset when connected as + // those APKs cannot select a LE Audio or Hearing Aid device explicitly. + AudioDeviceAttributes device = null; + if (communnicationDeviceCompatOn()) { + // If both LE and Hearing Aid are active (thie should not happen), + // priority to Hearing Aid. + device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID); + if (device == null) { + device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET); + } + } + return device; + } + @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) { synchronized (mDeviceStateLock) { return mDeviceInventory.getDeviceSensorUuid(device); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index c1f496905dba..35da73ef58c0 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -294,6 +294,7 @@ public class AudioDeviceInventory { } } + // @GuardedBy("AudioDeviceBroker.mSetModeLock") @GuardedBy("AudioDeviceBroker.mDeviceStateLock") void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) { if (AudioService.DEBUG_DEVICES) { @@ -376,7 +377,8 @@ public class AudioDeviceInventory { makeLeAudioDeviceUnavailable(address, btInfo.mAudioSystemDevice); } else if (switchToAvailable) { makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), - streamType, btInfo.mVolume, btInfo.mAudioSystemDevice, + streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10, + btInfo.mAudioSystemDevice, "onSetBtActiveDevice"); } break; @@ -1526,6 +1528,19 @@ public class AudioDeviceInventory { return di.mSensorUuid; } } + + /* package */ AudioDeviceAttributes getDeviceOfType(int type) { + synchronized (mDevicesLock) { + for (DeviceInfo di : mConnectedDevices.values()) { + if (di.mDeviceType == type) { + return new AudioDeviceAttributes( + di.mDeviceType, di.mDeviceAddress, di.mDeviceName); + } + } + } + return null; + } + //---------------------------------------------------------- // For tests only diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 56874f74afb1..c69eae3ede76 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3841,7 +3841,7 @@ public class AudioService extends IAudioService.Stub } } - private void setLeAudioVolumeOnModeUpdate(int mode) { + private void setLeAudioVolumeOnModeUpdate(int mode, int streamType, int device) { switch (mode) { case AudioSystem.MODE_IN_COMMUNICATION: case AudioSystem.MODE_IN_CALL: @@ -3857,8 +3857,6 @@ public class AudioService extends IAudioService.Stub return; } - int streamType = getBluetoothContextualVolumeStream(mode); - // Currently, DEVICE_OUT_BLE_HEADSET is the only output type for LE_AUDIO profile. // (See AudioDeviceBroker#createBtDeviceInfo()) int index = mStreamStates[streamType].getIndex(AudioSystem.DEVICE_OUT_BLE_HEADSET); @@ -3869,6 +3867,7 @@ public class AudioService extends IAudioService.Stub + index + " maxIndex=" + maxIndex + " streamType=" + streamType); } mDeviceBroker.postSetLeAudioVolumeIndex(index, maxIndex, streamType); + mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "setLeAudioVolumeOnModeUpdate"); } private void setStreamVolume(int streamType, int index, int flags, String callingPackage, @@ -5053,16 +5052,17 @@ public class AudioService extends IAudioService.Stub } /** - * Return the pid of the current audio mode owner + * Return information on the current audio mode owner * @return 0 if nobody owns the mode */ @GuardedBy("mDeviceBroker.mSetModeLock") - /*package*/ int getModeOwnerPid() { + /*package*/ AudioDeviceBroker.AudioModeInfo getAudioModeOwner() { SetModeDeathHandler hdlr = getAudioModeOwnerHandler(); if (hdlr != null) { - return hdlr.getPid(); + return new AudioDeviceBroker.AudioModeInfo( + hdlr.getMode(), hdlr.getPid(), hdlr.getUid()); } - return 0; + return new AudioDeviceBroker.AudioModeInfo(AudioSystem.MODE_NORMAL, 0 , 0); } /** @@ -5244,11 +5244,11 @@ public class AudioService extends IAudioService.Stub // Forcefully set LE audio volume as a workaround, since the value of 'device' // is not DEVICE_OUT_BLE_* even when BLE is connected. - setLeAudioVolumeOnModeUpdate(mode); + setLeAudioVolumeOnModeUpdate(mode, streamType, device); // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO // connections not started by the application changing the mode when pid changes - mDeviceBroker.postSetModeOwnerPid(pid, mode); + mDeviceBroker.postSetModeOwner(mode, pid, uid); } else { Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode); } @@ -5575,7 +5575,10 @@ public class AudioService extends IAudioService.Stub } return deviceIds.stream().mapToInt(Integer::intValue).toArray(); } - /** @see AudioManager#setCommunicationDevice(int) */ + /** + * @see AudioManager#setCommunicationDevice(int) + * @see AudioManager#clearCommunicationDevice() + */ public boolean setCommunicationDevice(IBinder cb, int portId) { final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); @@ -5590,7 +5593,8 @@ public class AudioService extends IAudioService.Stub throw new IllegalArgumentException("invalid device type " + device.getType()); } } - final String eventSource = new StringBuilder("setCommunicationDevice(") + final String eventSource = new StringBuilder() + .append(device == null ? "clearCommunicationDevice(" : "setCommunicationDevice(") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index b3e7e31d37fc..93841fe288e1 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -49,6 +49,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Consumer; /** @@ -104,11 +105,7 @@ public final class PlaybackActivityMonitor private static final VolumeShaper.Operation PLAY_SKIP_RAMP = new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build(); - private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>(); - // a public client is one that needs an anonymized version of the playback configurations, we - // keep track of whether there is at least one to know when we need to create the list of - // playback configurations that do not contain uid/pid/package name information. - private boolean mHasPublicClients = false; + private final ConcurrentLinkedQueue<PlayMonitorClient> mClients = new ConcurrentLinkedQueue<>(); private final Object mPlayerLock = new Object(); @GuardedBy("mPlayerLock") @@ -458,11 +455,9 @@ public final class PlaybackActivityMonitor + DateFormat.getTimeInstance().format(new Date())); synchronized(mPlayerLock) { pw.println("\n playback listeners:"); - synchronized(mClients) { - for (PlayMonitorClient pmc : mClients) { - pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)") - + pmc.toString()); - } + for (PlayMonitorClient pmc : mClients) { + pw.print(" " + (pmc.isPrivileged() ? "(S)" : "(P)") + + pmc.toString()); } pw.println("\n"); // all players @@ -534,48 +529,33 @@ public final class PlaybackActivityMonitor * @param iplayerReleased indicates if the change was due to a player being released */ private void dispatchPlaybackChange(boolean iplayerReleased) { - synchronized (mClients) { - // typical use case, nobody is listening, don't do any work - if (mClients.isEmpty()) { - return; - } - } if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); } final List<AudioPlaybackConfiguration> configsSystem; - // list of playback configurations for "public consumption". It is only computed if there + // list of playback configurations for "public consumption". It is computed lazy if there // are non-system playback activity listeners. - final List<AudioPlaybackConfiguration> configsPublic; + List<AudioPlaybackConfiguration> configsPublic = null; synchronized (mPlayerLock) { if (mPlayers.isEmpty()) { return; } - configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values()); + configsSystem = new ArrayList<>(mPlayers.values()); } - synchronized (mClients) { - // was done at beginning of method, but could have changed - if (mClients.isEmpty()) { - return; - } - configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null; - final Iterator<PlayMonitorClient> clientIterator = mClients.iterator(); - while (clientIterator.hasNext()) { - final PlayMonitorClient pmc = clientIterator.next(); - try { - // do not spam the logs if there are problems communicating with this client - if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) { - if (pmc.mIsPrivileged) { - pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem, - iplayerReleased); - } else { - // non-system clients don't have the control interface IPlayer, so - // they don't need to flush commands when a player was released - pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false); - } + + final Iterator<PlayMonitorClient> clientIterator = mClients.iterator(); + while (clientIterator.hasNext()) { + final PlayMonitorClient pmc = clientIterator.next(); + // do not spam the logs if there are problems communicating with this client + if (!pmc.reachedMaxErrorCount()) { + if (pmc.isPrivileged()) { + pmc.dispatchPlaybackConfigChange(configsSystem, + iplayerReleased); + } else { + if (configsPublic == null) { + configsPublic = anonymizeForPublicConsumption(configsSystem); } - } catch (RemoteException e) { - pmc.mErrorCount++; - Log.e(TAG, "Error (" + pmc.mErrorCount + - ") trying to dispatch playback config change to " + pmc, e); + // non-system clients don't have the control interface IPlayer, so + // they don't need to flush commands when a player was released + pmc.dispatchPlaybackConfigChange(configsPublic, false); } } } @@ -798,14 +778,9 @@ public final class PlaybackActivityMonitor if (pcdb == null) { return; } - synchronized(mClients) { - final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged); - if (pmc.init()) { - if (!isPrivileged) { - mHasPublicClients = true; - } - mClients.add(pmc); - } + final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged); + if (pmc.init()) { + mClients.add(pmc); } } @@ -813,23 +788,14 @@ public final class PlaybackActivityMonitor if (pcdb == null) { return; } - synchronized(mClients) { - final Iterator<PlayMonitorClient> clientIterator = mClients.iterator(); - boolean hasPublicClients = false; - // iterate over the clients to remove the dispatcher to remove, and reevaluate at - // the same time if we still have a public client. - while (clientIterator.hasNext()) { - PlayMonitorClient pmc = clientIterator.next(); - if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) { - pmc.release(); - clientIterator.remove(); - } else { - if (!pmc.mIsPrivileged) { - hasPublicClients = true; - } - } + final Iterator<PlayMonitorClient> clientIterator = mClients.iterator(); + // iterate over the clients to remove the dispatcher + while (clientIterator.hasNext()) { + PlayMonitorClient pmc = clientIterator.next(); + if (pmc.equalsDispatcher(pcdb)) { + pmc.release(); + clientIterator.remove(); } - mHasPublicClients = hasPublicClients; } } @@ -857,24 +823,34 @@ public final class PlaybackActivityMonitor // can afford to be static because only one PlaybackActivityMonitor ever instantiated static PlaybackActivityMonitor sListenerDeathMonitor; - final IPlaybackConfigDispatcher mDispatcherCb; - final boolean mIsPrivileged; - - int mErrorCount = 0; // number of errors after which we don't update this client anymore to not spam the logs - static final int MAX_ERRORS = 5; + private static final int MAX_ERRORS = 5; + + private final IPlaybackConfigDispatcher mDispatcherCb; + + @GuardedBy("this") + private final boolean mIsPrivileged; + @GuardedBy("this") + private boolean mIsReleased = false; + @GuardedBy("this") + private int mErrorCount = 0; PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) { mDispatcherCb = pcdb; mIsPrivileged = isPrivileged; } + @Override public void binderDied() { Log.w(TAG, "client died"); sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb); } - boolean init() { + synchronized boolean init() { + if (mIsReleased) { + // Do not init after release + return false; + } try { mDispatcherCb.asBinder().linkToDeath(this, 0); return true; @@ -884,8 +860,43 @@ public final class PlaybackActivityMonitor } } - void release() { + synchronized void release() { mDispatcherCb.asBinder().unlinkToDeath(this, 0); + mIsReleased = true; + } + + void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, + boolean flush) { + synchronized (this) { + if (mIsReleased) { + // Do not dispatch anything after release + return; + } + } + try { + mDispatcherCb.dispatchPlaybackConfigChange(configs, flush); + } catch (RemoteException e) { + synchronized (this) { + mErrorCount++; + Log.e(TAG, "Error (" + mErrorCount + + ") trying to dispatch playback config change to " + this, e); + } + } + } + + synchronized boolean isPrivileged() { + return mIsPrivileged; + } + + synchronized boolean reachedMaxErrorCount() { + return mErrorCount >= MAX_ERRORS; + } + + synchronized boolean equalsDispatcher(IPlaybackConfigDispatcher pcdb) { + if (pcdb == null) { + return false; + } + return pcdb.asBinder().equals(mDispatcherCb.asBinder()); } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 6a53978175af..6795b6b4158d 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONTROL_VPN; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; @@ -51,6 +52,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; +import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.DnsResolver; import android.net.INetd; @@ -234,6 +236,7 @@ public class Vpn { private final Context mContext; private final ConnectivityManager mConnectivityManager; private final AppOpsManager mAppOpsManager; + private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager; // The context is for specific user which is created from mUserId private final Context mUserIdContext; @VisibleForTesting final Dependencies mDeps; @@ -549,6 +552,8 @@ public class Vpn { mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); + mConnectivityDiagnosticsManager = + mContext.getSystemService(ConnectivityDiagnosticsManager.class); mDeps = deps; mNms = netService; mNetd = netd; @@ -2739,6 +2744,7 @@ public class Vpn { @Nullable private IkeSessionWrapper mSession; @Nullable private IkeSessionConnectionInfo mIkeConnectionInfo; + @Nullable private VpnConnectivityDiagnosticsCallback mDiagnosticsCallback; // mMobikeEnabled can only be updated after IKE AUTH is finished. private boolean mMobikeEnabled = false; @@ -2797,6 +2803,15 @@ public class Vpn { mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback, new Handler(mLooper)); } + + // DiagnosticsCallback may return more than one alive VPNs, but VPN will filter based on + // Network object. + final NetworkRequest diagRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_VPN) + .removeCapability(NET_CAPABILITY_NOT_VPN).build(); + mDiagnosticsCallback = new VpnConnectivityDiagnosticsCallback(); + mConnectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback( + diagRequest, mExecutor, mDiagnosticsCallback); } private boolean isActiveNetwork(@Nullable Network network) { @@ -3066,22 +3081,28 @@ public class Vpn { return; } - try { - 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 " - + underlyingNetwork); - mSession.setNetwork(underlyingNetwork); - return; - } + if (maybeMigrateIkeSession(underlyingNetwork)) return; + + startIkeSession(underlyingNetwork); + } - Log.d(TAG, "Start new IKE session on network " + underlyingNetwork); + boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) { + if (mSession == null || !mMobikeEnabled) return false; + // 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 " + + underlyingNetwork); + mSession.setNetwork(underlyingNetwork); + return true; + } + + private void startIkeSession(@NonNull Network underlyingNetwork) { + Log.d(TAG, "Start new IKE session on network " + underlyingNetwork); + + try { // Clear mInterface to prevent Ikev2VpnRunner being cleared when // interfaceRemoved() is called. synchronized (Vpn.this) { @@ -3169,6 +3190,28 @@ public class Vpn { mUnderlyingLinkProperties = lp; } + class VpnConnectivityDiagnosticsCallback + extends ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback { + // The callback runs in the executor thread. + @Override + public void onDataStallSuspected( + ConnectivityDiagnosticsManager.DataStallReport report) { + synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return; + + // Handle the report only for current VPN network. + if (mNetworkAgent != null + && mNetworkAgent.getNetwork().equals(report.getNetwork())) { + Log.d(TAG, "Data stall suspected"); + + // Trigger MOBIKE. + maybeMigrateIkeSession(mActiveNetwork); + } + } + } + } + /** * Handles loss of the default underlying network * @@ -3463,6 +3506,8 @@ public class Vpn { resetIkeState(); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); + mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback( + mDiagnosticsCallback); mExecutor.shutdown(); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 6a57e4070f65..070acd0b6183 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1551,8 +1551,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be // done in HighBrightnessModeController. if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR - && ((mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0 - || (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0)) { + && (mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0 + && (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0) { // We want to scale HDR brightness level with the SDR level animateValue = mHbmController.getHdrBrightnessValue(); } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 7d35fc5c8bd5..f8a74f4f3f55 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -266,10 +266,6 @@ public class HdmiControlService extends SystemService { // Make sure HdmiCecConfig is instantiated and the XMLs are read. private HdmiCecConfig mHdmiCecConfig; - // Last return value of getPhysicalAddress(). Only updated on calls of getPhysicalAddress(). - // Does not represent the current physical address at all times. Not to be used as a cache. - private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; - /** * Interface to report send result. */ @@ -2084,15 +2080,9 @@ public class HdmiControlService extends SystemService { @Override public int getPhysicalAddress() { initBinderCall(); - runOnServiceThread(new Runnable() { - @Override - public void run() { - synchronized (mLock) { - mPhysicalAddress = mHdmiCecNetwork.getPhysicalAddress(); - } - } - }); - return mPhysicalAddress; + synchronized (mLock) { + return mHdmiCecNetwork.getPhysicalAddress(); + } } @Override diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS index 7577ee5c9fde..55b0cffb32df 100644 --- a/services/core/java/com/android/server/locksettings/OWNERS +++ b/services/core/java/com/android/server/locksettings/OWNERS @@ -1,4 +1,3 @@ +ebiggers@google.com jaggies@google.com -kchyn@google.com rubinxu@google.com -xunchang@google.com diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index a4f10ba05106..018a2fc734b8 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7072,6 +7072,7 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mNotificationLock") void snoozeLocked(NotificationRecord r) { + final List<NotificationRecord> recordsToSnooze = new ArrayList<>(); if (r.getSbn().isGroup()) { final List<NotificationRecord> groupNotifications = findCurrentAndSnoozedGroupNotificationsLocked( @@ -7080,8 +7081,8 @@ public class NotificationManagerService extends SystemService { if (r.getNotification().isGroupSummary()) { // snooze all children for (int i = 0; i < groupNotifications.size(); i++) { - if (mKey != groupNotifications.get(i).getKey()) { - snoozeNotificationLocked(groupNotifications.get(i)); + if (!mKey.equals(groupNotifications.get(i).getKey())) { + recordsToSnooze.add(groupNotifications.get(i)); } } } else { @@ -7091,8 +7092,8 @@ public class NotificationManagerService extends SystemService { if (groupNotifications.size() == 2) { // snooze summary and the one child for (int i = 0; i < groupNotifications.size(); i++) { - if (mKey != groupNotifications.get(i).getKey()) { - snoozeNotificationLocked(groupNotifications.get(i)); + if (!mKey.equals(groupNotifications.get(i).getKey())) { + recordsToSnooze.add(groupNotifications.get(i)); } } } @@ -7100,7 +7101,15 @@ public class NotificationManagerService extends SystemService { } } // snooze the notification - snoozeNotificationLocked(r); + recordsToSnooze.add(r); + + if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) { + for (int i = 0; i < recordsToSnooze.size(); i++) { + snoozeNotificationLocked(recordsToSnooze.get(i)); + } + } else { + Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications"); + } } diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index 7f265df3f416..15d7c1e7a210 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -62,6 +62,8 @@ import java.util.Set; public class SnoozeHelper { public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1; + static final int CONCURRENT_SNOOZE_LIMIT = 500; + protected static final String XML_TAG_NAME = "snoozed-notifications"; private static final String XML_SNOOZED_NOTIFICATION = "notification"; @@ -135,6 +137,15 @@ public class SnoozeHelper { } } + protected boolean canSnooze(int numberToSnooze) { + synchronized (mLock) { + if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) { + return false; + } + } + return true; + } + @NonNull protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) { Long time = null; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 9e0c97502c4f..2b00ad7c5cd7 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -330,7 +330,8 @@ public class ZenModeHelper { int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner()) + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity()) + 1; - if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE + int newPackageRuleCount = getPackageRuleCount(pkg) + 1; + if (newPackageRuleCount > RULE_LIMIT_PER_PACKAGE || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) { throw new IllegalArgumentException("Rule instance limit exceeded"); } @@ -511,6 +512,23 @@ public class ZenModeHelper { return count; } + // Equivalent method to getCurrentInstanceCount, but for all rules associated with a specific + // package rather than a condition provider service or activity. + private int getPackageRuleCount(String pkg) { + if (pkg == null) { + return 0; + } + int count = 0; + synchronized (mConfig) { + for (ZenRule rule : mConfig.automaticRules.values()) { + if (pkg.equals(rule.getPkg())) { + count++; + } + } + } + return count; + } + public boolean canManageAutomaticZenRule(ZenRule rule) { final int callingUid = Binder.getCallingUid(); if (callingUid == 0 || callingUid == Process.SYSTEM_UID) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 1eb74facb840..46691a61930e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -314,6 +314,8 @@ class PackageManagerShellCommand extends ShellCommand { return runRemoveUser(); case "set-user-restriction": return runSetUserRestriction(); + case "supports-multiple-users": + return runSupportsMultipleUsers(); case "get-max-users": return runGetMaxUsers(); case "get-max-running-users": @@ -3014,6 +3016,12 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + public int runSupportsMultipleUsers() { + getOutPrintWriter().println("Is multiuser supported: " + + UserManager.supportsMultipleUsers()); + return 0; + } + public int runGetMaxUsers() { getOutPrintWriter().println("Maximum supported users: " + UserManager.getMaxSupportedUsers()); diff --git a/services/core/java/com/android/server/resources/OWNERS b/services/core/java/com/android/server/resources/OWNERS new file mode 100644 index 000000000000..7460a14182e5 --- /dev/null +++ b/services/core/java/com/android/server/resources/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 568761 + +patb@google.com +zyy@google.com diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index d0b058b4c8f2..e197319707e3 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1337,6 +1337,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } FgThread.getHandler().removeCallbacks(mResetRunnable); mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); + mContext.getMainThreadHandler().removeCallbacks(mDisconnectRunnable); } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ab936a6954d6..83687e9ebccd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4884,8 +4884,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ActivityOptions takeOptions() { if (DEBUG_TRANSITION) Slog.i(TAG, "Taking options for " + this + " callers=" + Debug.getCallers(6)); + if (mPendingOptions == null) return null; final ActivityOptions opts = mPendingOptions; mPendingOptions = null; + // Strip sensitive information from options before sending it to app. + opts.setRemoteTransition(null); + opts.setRemoteAnimationAdapter(null); return opts; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index d190b4f07121..8d831d72c05b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1441,6 +1441,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; a.resizeMode = RESIZE_MODE_UNRESIZEABLE; + a.configChanges = ActivityInfo.CONFIG_ORIENTATION; final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchActivityType(ACTIVITY_TYPE_DREAM); diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index f83173bd46c0..0bb773ae5e41 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -220,6 +220,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/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 1b0c01816f73..9050d79d714f 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1695,7 +1695,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev); prev = prev.completeFinishing(false /* updateVisibility */, "completePausedLocked"); - } else if (prev.hasProcess()) { + } else if (prev.attachedToProcess()) { ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s " + "wasStopping=%b visibleRequested=%b", prev, wasStopping, prev.mVisibleRequested); diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index 9abf107c780a..2584b86f53db 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -12,6 +12,7 @@ per-file com_android_server_power_PowerManagerService.* = michaelwr@google.com, per-file com_android_server_am_BatteryStatsService.cpp = file:/BATTERY_STATS_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION} +per-file com_android_server_SystemClock* = file:/services/core/java/com/android/server/timedetector/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 diff --git a/services/core/jni/com_android_server_companion_virtual_InputController.cpp b/services/core/jni/com_android_server_companion_virtual_InputController.cpp index 8197b67355d4..daca1531d41f 100644 --- a/services/core/jni/com_android_server_companion_virtual_InputController.cpp +++ b/services/core/jni/com_android_server_companion_virtual_InputController.cpp @@ -21,6 +21,7 @@ #include <android/keycodes.h> #include <errno.h> #include <fcntl.h> +#include <input/Input.h> #include <linux/uinput.h> #include <math.h> #include <nativehelper/JNIHelp.h> @@ -271,6 +272,14 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno)); return -errno; } + uinput_abs_setup slotAbsSetup; + slotAbsSetup.code = ABS_MT_SLOT; + slotAbsSetup.absinfo.maximum = MAX_POINTERS; + slotAbsSetup.absinfo.minimum = 0; + if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) { + ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno)); + return -errno; + } } if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) { ALOGE("Error creating uinput device: %s", strerror(errno)); diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 6196c49c88ce..9c9b363b948e 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -1287,8 +1287,8 @@ int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage, bp.set_allocated_dest_path(&target); bp.set_allocated_source_subdir(&source); const auto metadata = bp.SerializeAsString(); - bp.release_dest_path(); - bp.release_source_subdir(); + static_cast<void>(bp.release_dest_path()); + static_cast<void>(bp.release_source_subdir()); mdFileName = makeBindMdName(); metadataFullPath = path::join(ifs.root, constants().mount, mdFileName); auto node = mIncFs->makeFile(ifs.control, metadataFullPath, 0444, idFromMetadata(metadata), diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 59d96d2393ef..d9d3d62e92e2 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -474,8 +474,8 @@ public: m.mutable_loader()->set_package_name("com.test"); m.mutable_loader()->set_arguments("com.uri"); const auto metadata = m.SerializeAsString(); - m.mutable_loader()->release_arguments(); - m.mutable_loader()->release_package_name(); + static_cast<void>(m.mutable_loader()->release_arguments()); + static_cast<void>(m.mutable_loader()->release_package_name()); return {metadata.begin(), metadata.end()}; } RawMetadata getStorageMetadata(const Control& control, std::string_view path) { @@ -492,8 +492,8 @@ public: bp.set_allocated_dest_path(&destPath); bp.set_allocated_source_subdir(&srcPath); const auto metadata = bp.SerializeAsString(); - bp.release_source_subdir(); - bp.release_dest_path(); + static_cast<void>(bp.release_source_subdir()); + static_cast<void>(bp.release_dest_path()); return std::vector<char>(metadata.begin(), metadata.end()); } }; 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..994df2288a5c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt @@ -392,7 +392,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { whenever(rule.mocks().appsFilter.getVisibilityAllowList( any(PackageDataSnapshot::class.java), argThat { it?.packageName == pkgSetting.packageName }, any(IntArray::class.java), - any() as ArrayMap<String, out PackageStateInternal> + any<ArrayMap<String, out PackageStateInternal>>() )) .thenReturn(list) } 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..30ec1632a622 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -39,6 +39,7 @@ 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 +254,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/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 709c928dad9c..480ad110f357 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3380,39 +3380,98 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception { + public void testSnoozeRunnable_tooManySnoozed_singleNotification() { final NotificationRecord notification = generateNotificationRecord( mTestNotificationChannel, 1, null, true); mService.addNotification(notification); - when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); + when(mSnoozeHelper.canSnooze(1)).thenReturn(false); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( - notification.getKey(), 100, null); + notification.getKey(), 100, null); snoozeNotificationRunnable.run(); - NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = + + verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); + assertThat(mService.getNotificationRecordCount()).isEqualTo(1); + } + + @Test + public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord notificationChild = generateNotificationRecord( + mTestNotificationChannel, 1, "group", false); + mService.addNotification(notification); + mService.addNotification(notificationChild); + + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); + when(mSnoozeHelper.canSnooze(2)).thenReturn(false); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + notificationChild.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); + assertThat(mService.getNotificationRecordCount()).isEqualTo(2); + } + + @Test + public void testSnoozeRunnable_tooManySnoozed_summaryNotification() { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, "group", true); + final NotificationRecord notificationChild = generateNotificationRecord( + mTestNotificationChannel, 12, "group", false); + final NotificationRecord notificationChild2 = generateNotificationRecord( + mTestNotificationChannel, 13, "group", false); + mService.addNotification(notification); + mService.addNotification(notificationChild); + mService.addNotification(notificationChild2); + + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); + when(mSnoozeHelper.canSnooze(3)).thenReturn(false); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = + mService.new SnoozeNotificationRunnable( + notification.getKey(), 100, null); + snoozeNotificationRunnable.run(); + + verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); + assertThat(mService.getNotificationRecordCount()).isEqualTo(3); + } + + @Test + public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() { + final NotificationRecord notification = generateNotificationRecord( + mTestNotificationChannel, 1, null, true); + mService.addNotification(notification); + when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); + + NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( notification.getKey(), 100, null); snoozeNotificationRunnable.run(); + snoozeNotificationRunnable.run(); // snooze twice verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); } @Test - public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception { + public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() { final NotificationRecord notification = generateNotificationRecord( mTestNotificationChannel, 1, "group", true); mService.addNotification(notification); when(mSnoozeHelper.getNotification(any())).thenReturn(notification); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( notification.getKey(), 100, null); snoozeNotificationRunnable.run(); - NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = - mService.new SnoozeNotificationRunnable( - notification.getKey(), 100, null); snoozeNotificationRunnable.run(); // snooze twice @@ -3430,6 +3489,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mSnoozeHelper.getNotification(any())).thenReturn(notification); when(mSnoozeHelper.getNotifications( anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>()); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( @@ -3439,8 +3499,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2))); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = mService.new SnoozeNotificationRunnable( - notification.getKey(), 100, null); - snoozeNotificationRunnable.run(); + notification2.getKey(), 100, null); + snoozeNotificationRunnable2.run(); // snooze twice verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong()); @@ -3454,6 +3514,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel, 2, "group", false); mService.addNotification(grouped); mService.addNotification(nonGrouped); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( @@ -3483,6 +3544,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(parent); mService.addNotification(child); mService.addNotification(child2); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( @@ -3504,6 +3566,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.addNotification(parent); mService.addNotification(child); mService.addNotification(child2); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( @@ -3529,6 +3592,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel, 2, "group", false); mService.addNotification(parent); mService.addNotification(child); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( @@ -3556,6 +3620,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord child = generateNotificationRecord( mTestNotificationChannel, 2, "group", false); mService.addNotification(child); + when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = mService.new SnoozeNotificationRunnable( diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 2ae2ef7162a5..8bead5774548 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -15,6 +15,7 @@ */ package com.android.server.notification; +import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT; import static com.android.server.notification.SnoozeHelper.EXTRA_KEY; import static junit.framework.Assert.assertEquals; @@ -281,6 +282,22 @@ public class SnoozeHelperTest extends UiServiceTestCase { } @Test + public void testSnoozeLimit() { + for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++ ) { + NotificationRecord r = getNotificationRecord("pkg", i, i+"", UserHandle.SYSTEM); + + assertTrue("cannot snooze record " + i, mSnoozeHelper.canSnooze(1)); + + if (i % 2 == 0) { + mSnoozeHelper.snooze(r, null); + } else { + mSnoozeHelper.snooze(r, 9000); + } + } + assertFalse(mSnoozeHelper.canSnooze(1)); + } + + @Test public void testCancelByApp() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index fd1536c5c0f1..4550b56f6fd0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -1622,7 +1622,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + // We need the package name to be something that's not "android" so there aren't any + // existing rules under that package. + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); assertNotNull(id); } try { @@ -1632,12 +1634,41 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay } + } + @Test + public void testAddAutomaticZenRule_beyondSystemLimit_differentComponents() { + // Make sure the system limit is enforced per-package even with different component provider + // names. + for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) { + ScheduleInfo si = new ScheduleInfo(); + si.startHour = i; + AutomaticZenRule zenRule = new AutomaticZenRule("name" + i, + null, + new ComponentName("android", "ScheduleConditionProvider" + i), + ZenModeConfig.toScheduleConditionId(si), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + assertNotNull(id); + } + try { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName("android", "ScheduleConditionProviderFinal"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + fail("allowed too many rules to be created"); + } catch (IllegalArgumentException e) { + // yay + } } @Test diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fd738d2b531c..70d82701da66 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -8995,7 +8995,8 @@ public class TelephonyManager { * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}) - * and {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. + * and {@link android.Manifest.permission#ACCESS_FINE_LOCATION} if includeLocationData is + * set to {@link #INCLUDE_LOCATION_DATA_FINE}. * * If the system-wide location switch is off, apps may still call this API, with the * following constraints: @@ -9009,7 +9010,10 @@ public class TelephonyManager { * </ol> * * @param includeLocationData Specifies if the caller would like to receive - * location related information. + * location related information. If this parameter is set to + * {@link #INCLUDE_LOCATION_DATA_FINE} then the application will be checked for + * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission and available + * location related information received during network scan will be sent to the caller. * @param request Contains all the RAT with bands/channels that need to be scanned. * @param executor The executor through which the callback should be invoked. Since the scan * request may trigger multiple callbacks and they must be invoked in the same order as @@ -9020,8 +9024,7 @@ public class TelephonyManager { */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { - android.Manifest.permission.MODIFY_PHONE_STATE, - Manifest.permission.ACCESS_FINE_LOCATION + android.Manifest.permission.MODIFY_PHONE_STATE }) public @Nullable NetworkScan requestNetworkScan( @IncludeLocationData int includeLocationData, diff --git a/tests/Codegen/Android.bp b/tests/Codegen/Android.bp index ddbf16817b94..7fbe3b37f99e 100644 --- a/tests/Codegen/Android.bp +++ b/tests/Codegen/Android.bp @@ -24,6 +24,14 @@ android_test { plugins: [ "staledataclass-annotation-processor", ], + // Exports needed for staledataclass-annotation-processor, see b/139342589. + javacflags: [ + "-J--add-modules=jdk.compiler", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + ], static_libs: [ "junit", "hamcrest", diff --git a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java b/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java index 2e515705a253..761efe4a8484 100644 --- a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java +++ b/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java @@ -110,7 +110,7 @@ public class FixVibrateSetting extends Activity implements View.OnClickListener private void test() { Intent intent = new Intent(this, FixVibrateSetting.class); - PendingIntent pending = PendingIntent.getActivity(this, 0, intent, 0); + PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); Notification n = new Notification.Builder(this) .setSmallIcon(R.drawable.stat_sys_warning) diff --git a/tests/HandwritingIme/OWNERS b/tests/HandwritingIme/OWNERS new file mode 100644 index 000000000000..6bb4b17ed4eb --- /dev/null +++ b/tests/HandwritingIme/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 34867 + +include /services/core/java/com/android/server/inputmethod/OWNERS diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index b7c4c5b28168..f2234fb64108 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -51,6 +51,7 @@ java_test_host { data: [ ":com.android.apex.apkrollback.test_v1", ":test.rebootless_apex_v1", + ":RollbackTest", ], } diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp index 77f98e88f1eb..a1b888aef934 100644 --- a/tests/TrustTests/Android.bp +++ b/tests/TrustTests/Android.bp @@ -24,7 +24,7 @@ android_test { static_libs: [ "androidx.test.rules", "androidx.test.ext.junit", - "androidx.test.uiautomator", + "androidx.test.uiautomator_uiautomator", "mockito-target-minus-junit4", "servicestests-utils", "truth-prebuilt", diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 23f6c88aad91..3787f3b96f08 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -51,8 +51,10 @@ std::optional<ResourceName> ToResourceName(const android::ResTable::resource_nam util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen)); std::optional<ResourceNamedTypeRef> type; + std::string converted; if (name_in.type) { - type = ParseResourceNamedType(util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen))); + converted = util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen)); + type = ParseResourceNamedType(converted); } else if (name_in.type8) { type = ParseResourceNamedType(StringPiece(name_in.type8, name_in.typeLen)); } else { @@ -85,9 +87,10 @@ std::optional<ResourceName> ToResourceName(const android::AssetManager2::Resourc name_out.package = std::string(name_in.package, name_in.package_len); std::optional<ResourceNamedTypeRef> type; + std::string converted; if (name_in.type16) { - type = - ParseResourceNamedType(util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len))); + converted = util::Utf16ToUtf8(StringPiece16(name_in.type16, name_in.type_len)); + type = ParseResourceNamedType(converted); } else if (name_in.type) { type = ParseResourceNamedType(StringPiece(name_in.type, name_in.type_len)); } else { diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index d8c76e297ec5..0170c4a4c54b 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -270,6 +270,8 @@ class LinkCommand : public Command { "Changes the name of the target package for overlay. Most useful\n" "when used in conjunction with --rename-manifest-package.", &options_.manifest_fixer_options.rename_overlay_target_package); + AddOptionalFlag("--rename-overlay-category", "Changes the category for the overlay.", + &options_.manifest_fixer_options.rename_overlay_category); AddOptionalFlagList("-0", "File suffix not to compress.", &options_.extensions_to_not_compress); AddOptionalSwitch("--no-compress", "Do not compress any resources.", diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index d432341a8cde..efa42a2ee1dc 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -449,13 +449,18 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action["attribution"]["inherit-from"]; manifest_action["original-package"]; manifest_action["overlay"].Action([&](xml::Element* el) -> bool { - if (!options_.rename_overlay_target_package) { - return true; + if (options_.rename_overlay_target_package) { + if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) { + attr->value = options_.rename_overlay_target_package.value(); + } } - - if (xml::Attribute* attr = - el->FindAttribute(xml::kSchemaAndroid, "targetPackage")) { - attr->value = options_.rename_overlay_target_package.value(); + if (options_.rename_overlay_category) { + if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "category")) { + attr->value = options_.rename_overlay_category.value(); + } else { + el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "category", + options_.rename_overlay_category.value()}); + } } return true; }); diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h index d5d1d1770e1c..a8707d9d8623 100644 --- a/tools/aapt2/link/ManifestFixer.h +++ b/tools/aapt2/link/ManifestFixer.h @@ -48,6 +48,9 @@ struct ManifestFixerOptions { // <overlay>. std::optional<std::string> rename_overlay_target_package; + // The category to use instead of the one defined in 'android:category' in <overlay>. + std::optional<std::string> rename_overlay_category; + // The version name to set if 'android:versionName' is not defined in <manifest> or if // replace_version is set. std::optional<std::string> version_name_default; diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 432f10bdab97..098d0be7f87d 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -351,6 +351,54 @@ TEST_F(ManifestFixerTest, EXPECT_THAT(attr->value, StrEq("com.android")); } +TEST_F(ManifestFixerTest, AddOverlayCategory) { + ManifestFixerOptions options; + options.rename_overlay_category = std::string("category"); + + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android"> + <overlay android:targetName="Customization" android:targetPackage="android" /> + </manifest>)EOF", + options); + ASSERT_THAT(doc, NotNull()); + + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); + + xml::Element* overlay_el = manifest_el->FindChild({}, "overlay"); + ASSERT_THAT(overlay_el, NotNull()); + + xml::Attribute* attr = overlay_el->FindAttribute(xml::kSchemaAndroid, "category"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("category")); +} + +TEST_F(ManifestFixerTest, OverrideOverlayCategory) { + ManifestFixerOptions options; + options.rename_overlay_category = std::string("category"); + + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android"> + <overlay android:targetName="Customization" + android:targetPackage="android" + android:category="yrogetac"/> + </manifest>)EOF", + options); + ASSERT_THAT(doc, NotNull()); + + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); + + xml::Element* overlay_el = manifest_el->FindChild({}, "overlay"); + ASSERT_THAT(overlay_el, NotNull()); + + xml::Attribute* attr = overlay_el->FindAttribute(xml::kSchemaAndroid, "category"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("category")); +} + TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { ManifestFixerOptions options; options.version_name_default = std::string("Beta"); diff --git a/tools/lint/OWNERS b/tools/lint/OWNERS index 2c526a1e239e..33e237d306fc 100644 --- a/tools/lint/OWNERS +++ b/tools/lint/OWNERS @@ -4,3 +4,6 @@ jsharkey@google.com per-file *CallingSettingsNonUserGetterMethods* = file:/packages/SettingsProvider/OWNERS per-file *RegisterReceiverFlagDetector* = jacobhobbie@google.com +# Android lint in the Android platform maintainers +colefaust@google.com +farivar@google.com 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..8f553abfee31 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 @@ -65,8 +65,16 @@ class EnforcePermissionDetector : Detector(), SourceCodeScanner { if (attr1[i].name != attr2[i].name) { return false } - val v1 = ConstantEvaluator.evaluate(context, attr1[i].value) - val v2 = ConstantEvaluator.evaluate(context, attr2[i].value) + val value1 = attr1[i].value + val value2 = attr2[i].value + if (value1 == null && value2 == null) { + continue + } + if (value1 == null || value2 == null) { + return false + } + val v1 = ConstantEvaluator.evaluate(context, value1) + val v2 = ConstantEvaluator.evaluate(context, value2) if (v1 != v2) { return false } diff --git a/tools/preload/loadclass/LoadClass.java b/tools/preload/loadclass/LoadClass.java index a71b6a8b145e..3f6658ab8c65 100644 --- a/tools/preload/loadclass/LoadClass.java +++ b/tools/preload/loadclass/LoadClass.java @@ -14,8 +14,8 @@ * limitations under the License. */ -import android.util.Log; import android.os.Debug; +import android.util.Log; /** * Loads a class, runs the garbage collector, and prints showmap output. @@ -28,7 +28,7 @@ class LoadClass { System.loadLibrary("android_runtime"); if (registerNatives() < 0) { - throw new RuntimeException("Error registering natives."); + throw new RuntimeException("Error registering natives."); } Debug.startAllocCounting(); @@ -46,7 +46,7 @@ class LoadClass { } } - System.gc(); + Runtime.getRuntime().gc(); int allocCount = Debug.getGlobalAllocCount(); int allocSize = Debug.getGlobalAllocSize(); @@ -73,7 +73,7 @@ class LoadClass { response.append(',').append(freedCount); response.append(',').append(freedSize); response.append(',').append(nativeHeapSize); - + System.out.println(response.toString()); } diff --git a/tools/processors/staledataclass/Android.bp b/tools/processors/staledataclass/Android.bp index 1e5097662a0a..2169c49a91a5 100644 --- a/tools/processors/staledataclass/Android.bp +++ b/tools/processors/staledataclass/Android.bp @@ -22,17 +22,13 @@ java_plugin { static_libs: [ "codegen-version-info", ], - // The --add-modules/exports flags below don't work for kotlinc yet, so pin this module to Java language level 8 (see b/139342589): - java_version: "1.8", - openjdk9: { - javacflags: [ - "--add-modules=jdk.compiler", - "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", - "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", - "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", - "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", - ], - }, + javacflags: [ + "--add-modules=jdk.compiler", + "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + ], use_tools_jar: true, } diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt index 27a8853a2219..1cef5b0c8dfb 100644 --- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt +++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE") package android.processor.staledataclass diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt index 0fb062f280e3..0b619488c49c 100644 --- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt +++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt @@ -39,7 +39,7 @@ fun main(args: Array<String>) { kotlin.system.exitProcess(2) } - val ancestorCollector = AncestorCollector(Opcodes.ASM7, null) + val ancestorCollector = AncestorCollector(Opcodes.ASM9, null) for (entry in zipFile.entries()) { if (entry.name.endsWith(".class")) { diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java index 863f976b8aff..67c5561f348d 100644 --- a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java +++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java @@ -28,7 +28,7 @@ public class TraceInjectionClassVisitor extends ClassVisitor { private final TraceInjectionConfiguration mParams; public TraceInjectionClassVisitor(ClassVisitor classVisitor, TraceInjectionConfiguration params) { - super(Opcodes.ASM7, classVisitor); + super(Opcodes.ASM9, classVisitor); mParams = params; } diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java index c2bbddcb5668..91e987dc72ee 100644 --- a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java +++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java @@ -61,7 +61,7 @@ public class TraceInjectionMethodAdapter extends AdviceAdapter { public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access, String name, String descriptor, TraceInjectionConfiguration params) { - super(Opcodes.ASM7, methodVisitor, access, name, descriptor); + super(Opcodes.ASM9, methodVisitor, access, name, descriptor); mParams = params; mIsConstructor = "<init>".equals(name); } @@ -157,7 +157,7 @@ public class TraceInjectionMethodAdapter extends AdviceAdapter { class TracingAnnotationVisitor extends AnnotationVisitor { TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) { - super(Opcodes.ASM7, annotationVisitor); + super(Opcodes.ASM9, annotationVisitor); } @Override |