diff options
183 files changed, 6531 insertions, 1508 deletions
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index 3f87a1c8b598..968478c3f338 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -9,8 +9,11 @@ LOCAL_SRC_FILES := \ src/android/os/ISomeService.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ + androidx.appcompat_appcompat \ androidx.test.rules \ androidx.annotation_annotation \ + apct-perftests-overlay-apps \ + apct-perftests-resources-manager-apps \ apct-perftests-utils \ guava @@ -25,5 +28,6 @@ LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script LOCAL_COMPATIBILITY_SUITE += device-tests +LOCAL_CERTIFICATE := platform -include $(BUILD_PACKAGE) +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml index a564a4d27fb3..525975d36772 100644 --- a/apct-tests/perftests/core/AndroidManifest.xml +++ b/apct-tests/perftests/core/AndroidManifest.xml @@ -5,8 +5,11 @@ <permission android:name="com.android.perftests.core.TestPermission" /> <uses-permission android:name="com.android.perftests.core.TestPermission" /> - <uses-permission - android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" /> + <uses-permission android:name="android.permission.DELETE_PACKAGES" /> + <uses-permission android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.INSTALL_PACKAGES"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/apct-tests/perftests/core/apps/overlay/Android.bp b/apct-tests/perftests/core/apps/overlay/Android.bp new file mode 100644 index 000000000000..7bee30ee9cb4 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/Android.bp @@ -0,0 +1,188 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +android_test_helper_app { + name: "Overlay0", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay0", + ] +} + +android_test_helper_app { + name: "Overlay1", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay1", + ] +} + +android_test_helper_app { + name: "Overlay2", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay2", + ] +} + +android_test_helper_app { + name: "Overlay3", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay3", + ] +} + +android_test_helper_app { + name: "Overlay4", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay4", + ] +} + +android_test_helper_app { + name: "Overlay5", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay5", + ] +} + +android_test_helper_app { + name: "Overlay6", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay6", + ] +} + +android_test_helper_app { + name: "Overlay7", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay7", + ] +} +android_test_helper_app { + name: "Overlay8", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay8", + ] +} + +android_test_helper_app { + name: "Overlay9", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay9", + ] +} + +android_test_helper_app { + name: "LargeOverlay0", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large0", + ] +} + +android_test_helper_app { + name: "LargeOverlay1", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large1", + ] +} + +android_test_helper_app { + name: "LargeOverlay2", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large2", + ] +} + +android_test_helper_app { + name: "LargeOverlay3", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large3", + ] +} + +android_test_helper_app { + name: "LargeOverlay4", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large4", + ] +} + +android_test_helper_app { + name: "LargeOverlay5", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large5", + ] +} + +android_test_helper_app { + name: "LargeOverlay6", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large6", + ] +} + +android_test_helper_app { + name: "LargeOverlay7", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large7", + ] +} + +android_test_helper_app { + name: "LargeOverlay8", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large8", + ] +} + +android_test_helper_app { + name: "LargeOverlay9", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large9", + ] +} + +java_library { + name: "apct-perftests-overlay-apps", + java_resources: [ + ":Overlay0", + ":Overlay1", + ":Overlay2", + ":Overlay3", + ":Overlay4", + ":Overlay5", + ":Overlay6", + ":Overlay7", + ":Overlay8", + ":Overlay9", + ":LargeOverlay0", + ":LargeOverlay1", + ":LargeOverlay2", + ":LargeOverlay3", + ":LargeOverlay4", + ":LargeOverlay5", + ":LargeOverlay6", + ":LargeOverlay7", + ":LargeOverlay8", + ":LargeOverlay9", + ], +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml b/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml new file mode 100644 index 000000000000..52f5a89bc9e4 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.perftests.overlay"> + <application android:hasCode="false" /> + <uses-sdk android:targetSdkVersion="29" /> + <overlay android:targetPackage="com.android.perftests.core" android:targetName="TestResources"/> +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/overlay/res/values/values.xml b/apct-tests/perftests/core/apps/overlay/res/values/values.xml new file mode 100644 index 000000000000..a1a8d83eb193 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/res/values/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="short_text">B</string> +</resources> diff --git a/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml b/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml new file mode 100644 index 000000000000..e74144648e32 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="short_text000">B</string> + <string name="short_text001">B</string> + <string name="short_text002">B</string> + <string name="short_text003">B</string> + <string name="short_text004">B</string> + <string name="short_text005">B</string> + <string name="short_text006">B</string> + <string name="short_text007">B</string> + <string name="short_text008">B</string> + <string name="short_text009">B</string> + <string name="short_text010">B</string> + <string name="short_text011">B</string> + <string name="short_text012">B</string> + <string name="short_text013">B</string> + <string name="short_text014">B</string> + <string name="short_text015">B</string> + <string name="short_text016">B</string> + <string name="short_text017">B</string> + <string name="short_text018">B</string> + <string name="short_text019">B</string> + <string name="short_text020">B</string> + <string name="short_text021">B</string> + <string name="short_text022">B</string> + <string name="short_text023">B</string> + <string name="short_text024">B</string> + <string name="short_text025">B</string> + <string name="short_text026">B</string> + <string name="short_text027">B</string> + <string name="short_text028">B</string> + <string name="short_text029">B</string> + <string name="short_text030">B</string> + <string name="short_text031">B</string> + <string name="short_text032">B</string> + <string name="short_text033">B</string> + <string name="short_text034">B</string> + <string name="short_text035">B</string> + <string name="short_text036">B</string> + <string name="short_text037">B</string> + <string name="short_text038">B</string> + <string name="short_text039">B</string> + <string name="short_text040">B</string> + <string name="short_text041">B</string> + <string name="short_text042">B</string> + <string name="short_text043">B</string> + <string name="short_text044">B</string> + <string name="short_text045">B</string> + <string name="short_text046">B</string> + <string name="short_text047">B</string> + <string name="short_text048">B</string> + <string name="short_text049">B</string> + <string name="short_text050">B</string> + <string name="short_text051">B</string> + <string name="short_text052">B</string> + <string name="short_text053">B</string> + <string name="short_text054">B</string> + <string name="short_text055">B</string> + <string name="short_text056">B</string> + <string name="short_text057">B</string> + <string name="short_text058">B</string> + <string name="short_text059">B</string> + <string name="short_text060">B</string> + <string name="short_text061">B</string> + <string name="short_text062">B</string> + <string name="short_text063">B</string> + <string name="short_text064">B</string> + <string name="short_text065">B</string> + <string name="short_text066">B</string> + <string name="short_text067">B</string> + <string name="short_text068">B</string> + <string name="short_text069">B</string> + <string name="short_text070">B</string> + <string name="short_text071">B</string> + <string name="short_text072">B</string> + <string name="short_text073">B</string> + <string name="short_text074">B</string> + <string name="short_text075">B</string> + <string name="short_text076">B</string> + <string name="short_text077">B</string> + <string name="short_text078">B</string> + <string name="short_text079">B</string> + <string name="short_text080">B</string> + <string name="short_text081">B</string> + <string name="short_text082">B</string> + <string name="short_text083">B</string> + <string name="short_text084">B</string> + <string name="short_text085">B</string> + <string name="short_text086">B</string> + <string name="short_text087">B</string> + <string name="short_text088">B</string> + <string name="short_text089">B</string> + <string name="short_text090">B</string> + <string name="short_text091">B</string> + <string name="short_text092">B</string> + <string name="short_text093">B</string> + <string name="short_text094">B</string> + <string name="short_text095">B</string> + <string name="short_text096">B</string> + <string name="short_text097">B</string> + <string name="short_text098">B</string> + <string name="short_text099">B</string> + <string name="short_text100">B</string> + <string name="short_text101">B</string> + <string name="short_text102">B</string> + <string name="short_text103">B</string> + <string name="short_text104">B</string> + <string name="short_text105">B</string> + <string name="short_text106">B</string> + <string name="short_text107">B</string> + <string name="short_text108">B</string> + <string name="short_text109">B</string> + <string name="short_text110">B</string> + <string name="short_text111">B</string> + <string name="short_text112">B</string> + <string name="short_text113">B</string> + <string name="short_text114">B</string> + <string name="short_text115">B</string> + <string name="short_text116">B</string> + <string name="short_text117">B</string> + <string name="short_text118">B</string> + <string name="short_text119">B</string> + <string name="short_text120">B</string> + <string name="short_text121">B</string> + <string name="short_text122">B</string> + <string name="short_text123">B</string> + <string name="short_text124">B</string> + <string name="short_text125">B</string> + <string name="short_text126">B</string> + <string name="short_text127">B</string> + <string name="short_text128">B</string> + <string name="short_text129">B</string> + <string name="short_text130">B</string> + <string name="short_text131">B</string> + <string name="short_text132">B</string> + <string name="short_text133">B</string> + <string name="short_text134">B</string> + <string name="short_text135">B</string> + <string name="short_text136">B</string> + <string name="short_text137">B</string> + <string name="short_text138">B</string> + <string name="short_text139">B</string> + <string name="short_text140">B</string> + <string name="short_text141">B</string> + <string name="short_text142">B</string> + <string name="short_text143">B</string> + <string name="short_text144">B</string> + <string name="short_text145">B</string> + <string name="short_text146">B</string> + <string name="short_text147">B</string> + <string name="short_text148">B</string> + <string name="short_text149">B</string> + <string name="short_text150">B</string> + <string name="short_text151">B</string> + <string name="short_text152">B</string> + <string name="short_text153">B</string> + <string name="short_text154">B</string> + <string name="short_text155">B</string> + <string name="short_text156">B</string> + <string name="short_text157">B</string> + <string name="short_text158">B</string> + <string name="short_text159">B</string> + <string name="short_text160">B</string> + <string name="short_text161">B</string> + <string name="short_text162">B</string> + <string name="short_text163">B</string> + <string name="short_text164">B</string> + <string name="short_text165">B</string> + <string name="short_text166">B</string> + <string name="short_text167">B</string> + <string name="short_text168">B</string> + <string name="short_text169">B</string> + <string name="short_text170">B</string> + <string name="short_text171">B</string> + <string name="short_text172">B</string> + <string name="short_text173">B</string> + <string name="short_text174">B</string> + <string name="short_text175">B</string> + <string name="short_text176">B</string> + <string name="short_text177">B</string> + <string name="short_text178">B</string> + <string name="short_text179">B</string> + <string name="short_text180">B</string> + <string name="short_text181">B</string> + <string name="short_text182">B</string> + <string name="short_text183">B</string> + <string name="short_text184">B</string> + <string name="short_text185">B</string> + <string name="short_text186">B</string> + <string name="short_text187">B</string> + <string name="short_text188">B</string> + <string name="short_text189">B</string> + <string name="short_text190">B</string> + <string name="short_text191">B</string> + <string name="short_text192">B</string> + <string name="short_text193">B</string> + <string name="short_text194">B</string> + <string name="short_text195">B</string> + <string name="short_text196">B</string> + <string name="short_text197">B</string> + <string name="short_text198">B</string> + <string name="short_text199">B</string> + <string name="short_text200">B</string> + <string name="short_text201">B</string> + <string name="short_text202">B</string> + <string name="short_text203">B</string> + <string name="short_text204">B</string> + <string name="short_text205">B</string> + <string name="short_text206">B</string> + <string name="short_text207">B</string> + <string name="short_text208">B</string> + <string name="short_text209">B</string> + <string name="short_text210">B</string> + <string name="short_text211">B</string> + <string name="short_text212">B</string> + <string name="short_text213">B</string> + <string name="short_text214">B</string> + <string name="short_text215">B</string> + <string name="short_text216">B</string> + <string name="short_text217">B</string> + <string name="short_text218">B</string> + <string name="short_text219">B</string> + <string name="short_text220">B</string> + <string name="short_text221">B</string> + <string name="short_text222">B</string> + <string name="short_text223">B</string> + <string name="short_text224">B</string> + <string name="short_text225">B</string> + <string name="short_text226">B</string> + <string name="short_text227">B</string> + <string name="short_text228">B</string> + <string name="short_text229">B</string> + <string name="short_text230">B</string> + <string name="short_text231">B</string> + <string name="short_text232">B</string> + <string name="short_text233">B</string> + <string name="short_text234">B</string> + <string name="short_text235">B</string> + <string name="short_text236">B</string> + <string name="short_text237">B</string> + <string name="short_text238">B</string> + <string name="short_text239">B</string> + <string name="short_text240">B</string> + <string name="short_text241">B</string> + <string name="short_text242">B</string> + <string name="short_text243">B</string> + <string name="short_text244">B</string> + <string name="short_text245">B</string> + <string name="short_text246">B</string> + <string name="short_text247">B</string> + <string name="short_text248">B</string> + <string name="short_text249">B</string> + <string name="short_text250">B</string> + <string name="short_text251">B</string> + <string name="short_text252">B</string> + <string name="short_text253">B</string> + <string name="short_text254">B</string> + <string name="short_text255">B</string> +</resources> diff --git a/apct-tests/perftests/core/apps/reources_manager/Android.bp b/apct-tests/perftests/core/apps/reources_manager/Android.bp new file mode 100644 index 000000000000..451613236140 --- /dev/null +++ b/apct-tests/perftests/core/apps/reources_manager/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +android_test_helper_app { + name: "LargeResourcesCompressed", + static_libs: [ "androidx.appcompat_appcompat" ], +} + +genrule { + name: "LargeResourcesUncompressed", + srcs: [ ":LargeResourcesCompressed" ], + out: ["LargeResourcesUncompressed.apk"], + cmd: "cp $(in) $(out) && unzip -o $(out) resources.arsc" + + " && zip $(out) resources.arsc" +} + +java_library { + name: "apct-perftests-resources-manager-apps", + java_resources: [ + ":LargeResourcesCompressed", + ":LargeResourcesUncompressed", + ], +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml b/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml new file mode 100644 index 000000000000..adb4e406c608 --- /dev/null +++ b/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="fake.android"> + <application android:hasCode="false" /> + <uses-sdk android:targetSdkVersion="29" /> +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/core/res/color/color_state_list.xml b/apct-tests/perftests/core/res/color/color_state_list.xml new file mode 100644 index 000000000000..142e47ae2738 --- /dev/null +++ b/apct-tests/perftests/core/res/color/color_state_list.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" + android:color="#000000" /> + <item android:state_pressed="true" + android:state_enabled="false" + android:color="#212121" /> + <item android:state_enabled="false" + android:color="#414141" /> + <item android:color="#616161" /> +</selector>
\ No newline at end of file diff --git a/apct-tests/perftests/core/res/values/overlayable.xml b/apct-tests/perftests/core/res/values/overlayable.xml new file mode 100644 index 000000000000..70cedd7b0b75 --- /dev/null +++ b/apct-tests/perftests/core/res/values/overlayable.xml @@ -0,0 +1,280 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <overlayable name="TestResources"> + <policy type="public"> + <item type="string" name="short_text" /> + <item type="string" name="short_text000" /> + <item type="string" name="short_text001" /> + <item type="string" name="short_text002" /> + <item type="string" name="short_text003" /> + <item type="string" name="short_text004" /> + <item type="string" name="short_text005" /> + <item type="string" name="short_text006" /> + <item type="string" name="short_text007" /> + <item type="string" name="short_text008" /> + <item type="string" name="short_text009" /> + <item type="string" name="short_text010" /> + <item type="string" name="short_text011" /> + <item type="string" name="short_text012" /> + <item type="string" name="short_text013" /> + <item type="string" name="short_text014" /> + <item type="string" name="short_text015" /> + <item type="string" name="short_text016" /> + <item type="string" name="short_text017" /> + <item type="string" name="short_text018" /> + <item type="string" name="short_text019" /> + <item type="string" name="short_text020" /> + <item type="string" name="short_text021" /> + <item type="string" name="short_text022" /> + <item type="string" name="short_text023" /> + <item type="string" name="short_text024" /> + <item type="string" name="short_text025" /> + <item type="string" name="short_text026" /> + <item type="string" name="short_text027" /> + <item type="string" name="short_text028" /> + <item type="string" name="short_text029" /> + <item type="string" name="short_text030" /> + <item type="string" name="short_text031" /> + <item type="string" name="short_text032" /> + <item type="string" name="short_text033" /> + <item type="string" name="short_text034" /> + <item type="string" name="short_text035" /> + <item type="string" name="short_text036" /> + <item type="string" name="short_text037" /> + <item type="string" name="short_text038" /> + <item type="string" name="short_text039" /> + <item type="string" name="short_text040" /> + <item type="string" name="short_text041" /> + <item type="string" name="short_text042" /> + <item type="string" name="short_text043" /> + <item type="string" name="short_text044" /> + <item type="string" name="short_text045" /> + <item type="string" name="short_text046" /> + <item type="string" name="short_text047" /> + <item type="string" name="short_text048" /> + <item type="string" name="short_text049" /> + <item type="string" name="short_text050" /> + <item type="string" name="short_text051" /> + <item type="string" name="short_text052" /> + <item type="string" name="short_text053" /> + <item type="string" name="short_text054" /> + <item type="string" name="short_text055" /> + <item type="string" name="short_text056" /> + <item type="string" name="short_text057" /> + <item type="string" name="short_text058" /> + <item type="string" name="short_text059" /> + <item type="string" name="short_text060" /> + <item type="string" name="short_text061" /> + <item type="string" name="short_text062" /> + <item type="string" name="short_text063" /> + <item type="string" name="short_text064" /> + <item type="string" name="short_text065" /> + <item type="string" name="short_text066" /> + <item type="string" name="short_text067" /> + <item type="string" name="short_text068" /> + <item type="string" name="short_text069" /> + <item type="string" name="short_text070" /> + <item type="string" name="short_text071" /> + <item type="string" name="short_text072" /> + <item type="string" name="short_text073" /> + <item type="string" name="short_text074" /> + <item type="string" name="short_text075" /> + <item type="string" name="short_text076" /> + <item type="string" name="short_text077" /> + <item type="string" name="short_text078" /> + <item type="string" name="short_text079" /> + <item type="string" name="short_text080" /> + <item type="string" name="short_text081" /> + <item type="string" name="short_text082" /> + <item type="string" name="short_text083" /> + <item type="string" name="short_text084" /> + <item type="string" name="short_text085" /> + <item type="string" name="short_text086" /> + <item type="string" name="short_text087" /> + <item type="string" name="short_text088" /> + <item type="string" name="short_text089" /> + <item type="string" name="short_text090" /> + <item type="string" name="short_text091" /> + <item type="string" name="short_text092" /> + <item type="string" name="short_text093" /> + <item type="string" name="short_text094" /> + <item type="string" name="short_text095" /> + <item type="string" name="short_text096" /> + <item type="string" name="short_text097" /> + <item type="string" name="short_text098" /> + <item type="string" name="short_text099" /> + <item type="string" name="short_text100" /> + <item type="string" name="short_text101" /> + <item type="string" name="short_text102" /> + <item type="string" name="short_text103" /> + <item type="string" name="short_text104" /> + <item type="string" name="short_text105" /> + <item type="string" name="short_text106" /> + <item type="string" name="short_text107" /> + <item type="string" name="short_text108" /> + <item type="string" name="short_text109" /> + <item type="string" name="short_text110" /> + <item type="string" name="short_text111" /> + <item type="string" name="short_text112" /> + <item type="string" name="short_text113" /> + <item type="string" name="short_text114" /> + <item type="string" name="short_text115" /> + <item type="string" name="short_text116" /> + <item type="string" name="short_text117" /> + <item type="string" name="short_text118" /> + <item type="string" name="short_text119" /> + <item type="string" name="short_text120" /> + <item type="string" name="short_text121" /> + <item type="string" name="short_text122" /> + <item type="string" name="short_text123" /> + <item type="string" name="short_text124" /> + <item type="string" name="short_text125" /> + <item type="string" name="short_text126" /> + <item type="string" name="short_text127" /> + <item type="string" name="short_text128" /> + <item type="string" name="short_text129" /> + <item type="string" name="short_text130" /> + <item type="string" name="short_text131" /> + <item type="string" name="short_text132" /> + <item type="string" name="short_text133" /> + <item type="string" name="short_text134" /> + <item type="string" name="short_text135" /> + <item type="string" name="short_text136" /> + <item type="string" name="short_text137" /> + <item type="string" name="short_text138" /> + <item type="string" name="short_text139" /> + <item type="string" name="short_text140" /> + <item type="string" name="short_text141" /> + <item type="string" name="short_text142" /> + <item type="string" name="short_text143" /> + <item type="string" name="short_text144" /> + <item type="string" name="short_text145" /> + <item type="string" name="short_text146" /> + <item type="string" name="short_text147" /> + <item type="string" name="short_text148" /> + <item type="string" name="short_text149" /> + <item type="string" name="short_text150" /> + <item type="string" name="short_text151" /> + <item type="string" name="short_text152" /> + <item type="string" name="short_text153" /> + <item type="string" name="short_text154" /> + <item type="string" name="short_text155" /> + <item type="string" name="short_text156" /> + <item type="string" name="short_text157" /> + <item type="string" name="short_text158" /> + <item type="string" name="short_text159" /> + <item type="string" name="short_text160" /> + <item type="string" name="short_text161" /> + <item type="string" name="short_text162" /> + <item type="string" name="short_text163" /> + <item type="string" name="short_text164" /> + <item type="string" name="short_text165" /> + <item type="string" name="short_text166" /> + <item type="string" name="short_text167" /> + <item type="string" name="short_text168" /> + <item type="string" name="short_text169" /> + <item type="string" name="short_text170" /> + <item type="string" name="short_text171" /> + <item type="string" name="short_text172" /> + <item type="string" name="short_text173" /> + <item type="string" name="short_text174" /> + <item type="string" name="short_text175" /> + <item type="string" name="short_text176" /> + <item type="string" name="short_text177" /> + <item type="string" name="short_text178" /> + <item type="string" name="short_text179" /> + <item type="string" name="short_text180" /> + <item type="string" name="short_text181" /> + <item type="string" name="short_text182" /> + <item type="string" name="short_text183" /> + <item type="string" name="short_text184" /> + <item type="string" name="short_text185" /> + <item type="string" name="short_text186" /> + <item type="string" name="short_text187" /> + <item type="string" name="short_text188" /> + <item type="string" name="short_text189" /> + <item type="string" name="short_text190" /> + <item type="string" name="short_text191" /> + <item type="string" name="short_text192" /> + <item type="string" name="short_text193" /> + <item type="string" name="short_text194" /> + <item type="string" name="short_text195" /> + <item type="string" name="short_text196" /> + <item type="string" name="short_text197" /> + <item type="string" name="short_text198" /> + <item type="string" name="short_text199" /> + <item type="string" name="short_text200" /> + <item type="string" name="short_text201" /> + <item type="string" name="short_text202" /> + <item type="string" name="short_text203" /> + <item type="string" name="short_text204" /> + <item type="string" name="short_text205" /> + <item type="string" name="short_text206" /> + <item type="string" name="short_text207" /> + <item type="string" name="short_text208" /> + <item type="string" name="short_text209" /> + <item type="string" name="short_text210" /> + <item type="string" name="short_text211" /> + <item type="string" name="short_text212" /> + <item type="string" name="short_text213" /> + <item type="string" name="short_text214" /> + <item type="string" name="short_text215" /> + <item type="string" name="short_text216" /> + <item type="string" name="short_text217" /> + <item type="string" name="short_text218" /> + <item type="string" name="short_text219" /> + <item type="string" name="short_text220" /> + <item type="string" name="short_text221" /> + <item type="string" name="short_text222" /> + <item type="string" name="short_text223" /> + <item type="string" name="short_text224" /> + <item type="string" name="short_text225" /> + <item type="string" name="short_text226" /> + <item type="string" name="short_text227" /> + <item type="string" name="short_text228" /> + <item type="string" name="short_text229" /> + <item type="string" name="short_text230" /> + <item type="string" name="short_text231" /> + <item type="string" name="short_text232" /> + <item type="string" name="short_text233" /> + <item type="string" name="short_text234" /> + <item type="string" name="short_text235" /> + <item type="string" name="short_text236" /> + <item type="string" name="short_text237" /> + <item type="string" name="short_text238" /> + <item type="string" name="short_text239" /> + <item type="string" name="short_text240" /> + <item type="string" name="short_text241" /> + <item type="string" name="short_text242" /> + <item type="string" name="short_text243" /> + <item type="string" name="short_text244" /> + <item type="string" name="short_text245" /> + <item type="string" name="short_text246" /> + <item type="string" name="short_text247" /> + <item type="string" name="short_text248" /> + <item type="string" name="short_text249" /> + <item type="string" name="short_text250" /> + <item type="string" name="short_text251" /> + <item type="string" name="short_text252" /> + <item type="string" name="short_text253" /> + <item type="string" name="short_text254" /> + <item type="string" name="short_text255" /> + </policy> + </overlayable> +</resources> diff --git a/apct-tests/perftests/core/res/values/strings.xml b/apct-tests/perftests/core/res/values/strings.xml deleted file mode 100644 index 7ab325f79dc7..000000000000 --- a/apct-tests/perftests/core/res/values/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2016 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="long_text">text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text typo text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text </string> - <string name="short_text">text text</string> -</resources> diff --git a/apct-tests/perftests/core/res/values/values.xml b/apct-tests/perftests/core/res/values/values.xml new file mode 100644 index 000000000000..aad42ba04e11 --- /dev/null +++ b/apct-tests/perftests/core/res/values/values.xml @@ -0,0 +1,368 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="long_text">text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text typo text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text </string> + + <plurals name="plurals_text"> + <item quantity="one">1 text</item> + <item quantity="other"><xliff:g id="count" example="3">%d</xliff:g> texts</item> + </plurals> + + <string-array name="strings"> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + </string-array> + + <integer-array name="ints"> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + </integer-array> + + <color name="white">#ffffff</color> + + <integer name="forty_two">42</integer> + + <string name="short_text">text text</string> + <string name="short_text000">B</string> + <string name="short_text001">B</string> + <string name="short_text002">B</string> + <string name="short_text003">B</string> + <string name="short_text004">B</string> + <string name="short_text005">B</string> + <string name="short_text006">B</string> + <string name="short_text007">B</string> + <string name="short_text008">B</string> + <string name="short_text009">B</string> + <string name="short_text010">B</string> + <string name="short_text011">B</string> + <string name="short_text012">B</string> + <string name="short_text013">B</string> + <string name="short_text014">B</string> + <string name="short_text015">B</string> + <string name="short_text016">B</string> + <string name="short_text017">B</string> + <string name="short_text018">B</string> + <string name="short_text019">B</string> + <string name="short_text020">B</string> + <string name="short_text021">B</string> + <string name="short_text022">B</string> + <string name="short_text023">B</string> + <string name="short_text024">B</string> + <string name="short_text025">B</string> + <string name="short_text026">B</string> + <string name="short_text027">B</string> + <string name="short_text028">B</string> + <string name="short_text029">B</string> + <string name="short_text030">B</string> + <string name="short_text031">B</string> + <string name="short_text032">B</string> + <string name="short_text033">B</string> + <string name="short_text034">B</string> + <string name="short_text035">B</string> + <string name="short_text036">B</string> + <string name="short_text037">B</string> + <string name="short_text038">B</string> + <string name="short_text039">B</string> + <string name="short_text040">B</string> + <string name="short_text041">B</string> + <string name="short_text042">B</string> + <string name="short_text043">B</string> + <string name="short_text044">B</string> + <string name="short_text045">B</string> + <string name="short_text046">B</string> + <string name="short_text047">B</string> + <string name="short_text048">B</string> + <string name="short_text049">B</string> + <string name="short_text050">B</string> + <string name="short_text051">B</string> + <string name="short_text052">B</string> + <string name="short_text053">B</string> + <string name="short_text054">B</string> + <string name="short_text055">B</string> + <string name="short_text056">B</string> + <string name="short_text057">B</string> + <string name="short_text058">B</string> + <string name="short_text059">B</string> + <string name="short_text060">B</string> + <string name="short_text061">B</string> + <string name="short_text062">B</string> + <string name="short_text063">B</string> + <string name="short_text064">B</string> + <string name="short_text065">B</string> + <string name="short_text066">B</string> + <string name="short_text067">B</string> + <string name="short_text068">B</string> + <string name="short_text069">B</string> + <string name="short_text070">B</string> + <string name="short_text071">B</string> + <string name="short_text072">B</string> + <string name="short_text073">B</string> + <string name="short_text074">B</string> + <string name="short_text075">B</string> + <string name="short_text076">B</string> + <string name="short_text077">B</string> + <string name="short_text078">B</string> + <string name="short_text079">B</string> + <string name="short_text080">B</string> + <string name="short_text081">B</string> + <string name="short_text082">B</string> + <string name="short_text083">B</string> + <string name="short_text084">B</string> + <string name="short_text085">B</string> + <string name="short_text086">B</string> + <string name="short_text087">B</string> + <string name="short_text088">B</string> + <string name="short_text089">B</string> + <string name="short_text090">B</string> + <string name="short_text091">B</string> + <string name="short_text092">B</string> + <string name="short_text093">B</string> + <string name="short_text094">B</string> + <string name="short_text095">B</string> + <string name="short_text096">B</string> + <string name="short_text097">B</string> + <string name="short_text098">B</string> + <string name="short_text099">B</string> + <string name="short_text100">B</string> + <string name="short_text101">B</string> + <string name="short_text102">B</string> + <string name="short_text103">B</string> + <string name="short_text104">B</string> + <string name="short_text105">B</string> + <string name="short_text106">B</string> + <string name="short_text107">B</string> + <string name="short_text108">B</string> + <string name="short_text109">B</string> + <string name="short_text110">B</string> + <string name="short_text111">B</string> + <string name="short_text112">B</string> + <string name="short_text113">B</string> + <string name="short_text114">B</string> + <string name="short_text115">B</string> + <string name="short_text116">B</string> + <string name="short_text117">B</string> + <string name="short_text118">B</string> + <string name="short_text119">B</string> + <string name="short_text120">B</string> + <string name="short_text121">B</string> + <string name="short_text122">B</string> + <string name="short_text123">B</string> + <string name="short_text124">B</string> + <string name="short_text125">B</string> + <string name="short_text126">B</string> + <string name="short_text127">B</string> + <string name="short_text128">B</string> + <string name="short_text129">B</string> + <string name="short_text130">B</string> + <string name="short_text131">B</string> + <string name="short_text132">B</string> + <string name="short_text133">B</string> + <string name="short_text134">B</string> + <string name="short_text135">B</string> + <string name="short_text136">B</string> + <string name="short_text137">B</string> + <string name="short_text138">B</string> + <string name="short_text139">B</string> + <string name="short_text140">B</string> + <string name="short_text141">B</string> + <string name="short_text142">B</string> + <string name="short_text143">B</string> + <string name="short_text144">B</string> + <string name="short_text145">B</string> + <string name="short_text146">B</string> + <string name="short_text147">B</string> + <string name="short_text148">B</string> + <string name="short_text149">B</string> + <string name="short_text150">B</string> + <string name="short_text151">B</string> + <string name="short_text152">B</string> + <string name="short_text153">B</string> + <string name="short_text154">B</string> + <string name="short_text155">B</string> + <string name="short_text156">B</string> + <string name="short_text157">B</string> + <string name="short_text158">B</string> + <string name="short_text159">B</string> + <string name="short_text160">B</string> + <string name="short_text161">B</string> + <string name="short_text162">B</string> + <string name="short_text163">B</string> + <string name="short_text164">B</string> + <string name="short_text165">B</string> + <string name="short_text166">B</string> + <string name="short_text167">B</string> + <string name="short_text168">B</string> + <string name="short_text169">B</string> + <string name="short_text170">B</string> + <string name="short_text171">B</string> + <string name="short_text172">B</string> + <string name="short_text173">B</string> + <string name="short_text174">B</string> + <string name="short_text175">B</string> + <string name="short_text176">B</string> + <string name="short_text177">B</string> + <string name="short_text178">B</string> + <string name="short_text179">B</string> + <string name="short_text180">B</string> + <string name="short_text181">B</string> + <string name="short_text182">B</string> + <string name="short_text183">B</string> + <string name="short_text184">B</string> + <string name="short_text185">B</string> + <string name="short_text186">B</string> + <string name="short_text187">B</string> + <string name="short_text188">B</string> + <string name="short_text189">B</string> + <string name="short_text190">B</string> + <string name="short_text191">B</string> + <string name="short_text192">B</string> + <string name="short_text193">B</string> + <string name="short_text194">B</string> + <string name="short_text195">B</string> + <string name="short_text196">B</string> + <string name="short_text197">B</string> + <string name="short_text198">B</string> + <string name="short_text199">B</string> + <string name="short_text200">B</string> + <string name="short_text201">B</string> + <string name="short_text202">B</string> + <string name="short_text203">B</string> + <string name="short_text204">B</string> + <string name="short_text205">B</string> + <string name="short_text206">B</string> + <string name="short_text207">B</string> + <string name="short_text208">B</string> + <string name="short_text209">B</string> + <string name="short_text210">B</string> + <string name="short_text211">B</string> + <string name="short_text212">B</string> + <string name="short_text213">B</string> + <string name="short_text214">B</string> + <string name="short_text215">B</string> + <string name="short_text216">B</string> + <string name="short_text217">B</string> + <string name="short_text218">B</string> + <string name="short_text219">B</string> + <string name="short_text220">B</string> + <string name="short_text221">B</string> + <string name="short_text222">B</string> + <string name="short_text223">B</string> + <string name="short_text224">B</string> + <string name="short_text225">B</string> + <string name="short_text226">B</string> + <string name="short_text227">B</string> + <string name="short_text228">B</string> + <string name="short_text229">B</string> + <string name="short_text230">B</string> + <string name="short_text231">B</string> + <string name="short_text232">B</string> + <string name="short_text233">B</string> + <string name="short_text234">B</string> + <string name="short_text235">B</string> + <string name="short_text236">B</string> + <string name="short_text237">B</string> + <string name="short_text238">B</string> + <string name="short_text239">B</string> + <string name="short_text240">B</string> + <string name="short_text241">B</string> + <string name="short_text242">B</string> + <string name="short_text243">B</string> + <string name="short_text244">B</string> + <string name="short_text245">B</string> + <string name="short_text246">B</string> + <string name="short_text247">B</string> + <string name="short_text248">B</string> + <string name="short_text249">B</string> + <string name="short_text250">B</string> + <string name="short_text251">B</string> + <string name="short_text252">B</string> + <string name="short_text253">B</string> + <string name="short_text254">B</string> + <string name="short_text255">B</string> +</resources> diff --git a/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java new file mode 100644 index 000000000000..fcb13a8d51f1 --- /dev/null +++ b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.content.om.OverlayManager; +import android.os.UserHandle; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.TestPackageInstaller; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import com.android.perftests.core.R; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +/** + * Benchmarks for {@link android.content.om.OverlayManager}. + */ +@LargeTest +public class OverlayManagerPerfTest { + private static final int OVERLAY_PKG_COUNT = 10; + private static Context sContext; + private static OverlayManager sOverlayManager; + private static Executor sExecutor; + private static ArrayList<TestPackageInstaller.InstalledPackage> sSmallOverlays = + new ArrayList<>(); + private static ArrayList<TestPackageInstaller.InstalledPackage> sLargeOverlays = + new ArrayList<>(); + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @BeforeClass + public static void classSetUp() throws Exception { + sContext = InstrumentationRegistry.getTargetContext(); + sOverlayManager = new OverlayManager(sContext); + sExecutor = (command) -> new Thread(command).start(); + + // Install all of the test overlays. + TestPackageInstaller installer = new TestPackageInstaller(sContext); + for (int i = 0; i < OVERLAY_PKG_COUNT; i++) { + sSmallOverlays.add(installer.installPackage("Overlay" + i +".apk")); + sLargeOverlays.add(installer.installPackage("LargeOverlay" + i +".apk")); + } + } + + @AfterClass + public static void classTearDown() throws Exception { + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + overlay.uninstall(); + } + + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + overlay.uninstall(); + } + } + + @After + public void tearDown() throws Exception { + // Disable all test overlays after each test. + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), false); + } + + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), false); + } + } + + /** + * Enables the overlay and waits for the APK path change sto be propagated to the context + * AssetManager. + */ + private void assertSetEnabled(Context context, String overlayPackage, boolean eanabled) + throws Exception { + sOverlayManager.setEnabled(overlayPackage, true, UserHandle.SYSTEM); + + // Wait for the overlay changes to propagate + FutureTask<Boolean> task = new FutureTask<>(() -> { + while (true) { + for (String path : context.getAssets().getApkPaths()) { + if (eanabled == path.contains(overlayPackage)) { + return true; + } + } + } + }); + + sExecutor.execute(task); + assertTrue("Failed to load overlay " + overlayPackage, + task.get(20, TimeUnit.SECONDS)); + } + + @Test + public void setEnabledWarmCache() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + state.resumeTiming(); + } + } + + @Test + public void setEnabledColdCacheSmallOverlay() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay and remove the idmap for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM); + state.resumeTiming(); + } + } + + @Test + public void setEnabledColdCacheLargeOverlay() throws Exception { + String packageName = sLargeOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay and remove the idmap for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM); + state.resumeTiming(); + } + } + + @Test + public void setEnabledDisable() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + assertSetEnabled(sContext, packageName, true); + state.resumeTiming(); + + assertSetEnabled(sContext, packageName, false); + } + } + + @Test + public void getStringOneSmallOverlay() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + assertSetEnabled(sContext, packageName, true); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + sContext.getString(R.string.short_text); + } + + assertSetEnabled(sContext, packageName, false); + } + + @Test + public void getStringOneLargeOverlay() throws Exception { + String packageName = sLargeOverlays.get(0).getPackageName(); + assertSetEnabled(sContext, packageName, true); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + for (int resId = R.string.short_text000; resId < R.string.short_text255; resId++) { + sContext.getString(resId); + } + } + + assertSetEnabled(sContext, packageName, false); + } + + @Test + public void getStringTenOverlays() throws Exception { + // Enable all test overlays + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), true); + } + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + sContext.getString(R.string.short_text); + } + } + + @Test + public void getStringLargeTenOverlays() throws Exception { + // Enable all test overlays + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), true); + } + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + for (int resId = R.string.short_text000; resId < R.string.short_text255; resId++) { + sContext.getString(resId); + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java new file mode 100644 index 000000000000..2955d2ca7d0e --- /dev/null +++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.app; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.view.Display; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Benchmarks for {@link android.app.ResourcesManager}. + */ +@LargeTest +public class ResourcesManagerPerfTest { + private static Context sContext; + private static File sResourcesCompressed; + private static File sResourcesUncompressed; + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @BeforeClass + public static void setUp() throws Exception { + sContext = InstrumentationRegistry.getTargetContext(); + sResourcesCompressed = copyApkToTemp("LargeResourcesCompressed.apk", + "LargeResourcesCompressed.apk"); + sResourcesUncompressed = copyApkToTemp("LargeResourcesUncompressed.apk", + "LargeResourcesUncompressed.apk"); + } + + @AfterClass + public static void tearDown() { + Assert.assertTrue(sResourcesCompressed.delete()); + Assert.assertTrue(sResourcesUncompressed.delete()); + } + + private static File copyApkToTemp(String inputFileName, String fileName) throws Exception { + File file = File.createTempFile(fileName, null, sContext.getCacheDir()); + try (OutputStream tempOutputStream = new FileOutputStream(file); + InputStream is = sContext.getResources().getAssets().openNonAsset(inputFileName)) { + byte[] buffer = new byte[4096]; + int n; + while ((n = is.read(buffer)) >= 0) { + tempOutputStream.write(buffer, 0, n); + } + tempOutputStream.flush(); + } + return file; + } + + private void getResourcesForPath(String path) { + ResourcesManager.getInstance().getResources(null, path, null, null, null, + Display.DEFAULT_DISPLAY, null, sContext.getResources().getCompatibilityInfo(), + null); + } + + @Test + public void getResourcesCached() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + getResourcesForPath(sResourcesCompressed.getPath()); + while (state.keepRunning()) { + getResourcesForPath(sResourcesCompressed.getPath()); + } + } + + @Test + public void getResourcesCompressedUncached() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + resourcesManager.invalidatePath(sResourcesCompressed.getPath()); + state.resumeTiming(); + + getResourcesForPath(sResourcesCompressed.getPath()); + } + } + + @Test + public void getResourcesUncompressedUncached() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + resourcesManager.invalidatePath(sResourcesUncompressed.getPath()); + state.resumeTiming(); + + getResourcesForPath(sResourcesUncompressed.getPath()); + } + } + + @Test + public void applyConfigurationToResourcesLocked() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + Configuration c = new Configuration(resourcesManager.getConfiguration()); + c.uiMode = Configuration.UI_MODE_TYPE_WATCH; + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + resourcesManager.applyConfigurationToResources(c, null); + + // Alternate configurations to ensure the set configuration is different each iteration + if (c.uiMode == Configuration.UI_MODE_TYPE_WATCH) { + c.uiMode = Configuration.UI_MODE_TYPE_TELEVISION; + } else { + c.uiMode = Configuration.UI_MODE_TYPE_WATCH; + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java index c3e43ee07453..72162448a2e0 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java @@ -18,15 +18,18 @@ package android.app; import static org.junit.Assert.fail; -import android.content.res.AssetManager; +import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.util.TypedValue; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import org.junit.After; +import com.android.perftests.core.R; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -43,36 +46,123 @@ public class ResourcesPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - private AssetManager mAsset; private Resources mRes; - private int mTextId; - private int mColorId; - private int mIntegerId; - private int mLayoutId; - @Before public void setUp() { - mAsset = new AssetManager(); - mAsset.addAssetPath("/system/framework/framework-res.apk"); - mRes = new Resources(mAsset, null, null); + Context context = InstrumentationRegistry.getTargetContext(); + mRes = context.getResources(); + } + + @Test + public void getValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(R.integer.forty_two, value, false /* resolve_refs */); + } + } - mTextId = mRes.getIdentifier("cancel", "string", "android"); - mColorId = mRes.getIdentifier("transparent", "color", "android"); - mIntegerId = mRes.getIdentifier("config_shortAnimTime", "integer", "android"); - mLayoutId = mRes.getIdentifier("two_line_list_item", "layout", "android"); + @Test + public void getFrameworkValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.integer.autofill_max_visible_datasets, value, + false /* resolve_refs */); + } + } + + @Test + public void getValueString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(R.string.long_text, value, false /* resolve_refs */); + } + } + + @Test + public void getFrameworkStringValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.string.cancel, value, false /* resolve_refs */); + } } - @After - public void tearDown() { - mAsset.close(); + @Test + public void getValueManyConfigurations() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.string.mmcc_illegal_me, value, + false /* resolve_refs */); + } } @Test public void getText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getText(mTextId); + mRes.getText(R.string.long_text); + } + } + + + @Test + public void getFont() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getFont(R.font.samplefont); + } + } + + @Test + public void getString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getString(R.string.long_text); + } + } + + @Test + public void getQuantityString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getQuantityString(R.plurals.plurals_text, 5); + } + } + + @Test + public void getQuantityText() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getQuantityText(R.plurals.plurals_text, 5); + } + } + + @Test + public void getTextArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getTextArray(R.array.strings); + } + } + + @Test + public void getStringArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getStringArray(R.array.strings); + } + } + + @Test + public void getIntegerArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getIntArray(R.array.ints); } } @@ -80,15 +170,23 @@ public class ResourcesPerfTest { public void getColor() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getColor(mColorId, null); + mRes.getColor(R.color.white, null); } } @Test - public void getInteger() { + public void getColorStateList() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getInteger(mIntegerId); + mRes.getColorStateList(R.color.color_state_list, null); + } + } + + @Test + public void getVectorDrawable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getDrawable(R.drawable.vector_drawable01, null); } } @@ -96,13 +194,32 @@ public class ResourcesPerfTest { public void getLayoutAndTravese() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - try (XmlResourceParser parser = mRes.getLayout(mLayoutId)) { + try (XmlResourceParser parser = mRes.getLayout(R.layout.test_relative_layout)) { + while (parser.next() != XmlPullParser.END_DOCUMENT) { + // Walk the entire tree + } + } catch (IOException | XmlPullParserException exception) { + fail("Parsing of the layout failed. Something is really broken"); + } + } + } + + @Test + public void getLayoutAndTraverseInvalidateCaches() { + mRes.flushLayoutCache(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + try (XmlResourceParser parser = mRes.getLayout(R.layout.test_relative_layout)) { while (parser.next() != XmlPullParser.END_DOCUMENT) { // Walk the entire tree } } catch (IOException | XmlPullParserException exception) { fail("Parsing of the layout failed. Something is really broken"); } + + state.pauseTiming(); + mRes.flushLayoutCache(); + state.resumeTiming(); } } -} +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java index 1b07572fd3f8..6123e69b584e 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java @@ -16,13 +16,19 @@ package android.app; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; +import android.os.UserHandle; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.view.Display; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -35,13 +41,69 @@ public class ResourcesThemePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + private Context mContext; + private int mThemeResId; private Resources.Theme mTheme; @Before - public void setUp() { - Context context = InstrumentationRegistry.getTargetContext(); - mTheme = context.getTheme(); + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + mThemeResId = com.android.perftests.core.R.style.Base_V7_Theme_AppCompat; + mTheme = mContext.getResources().newTheme(); + mTheme.applyStyle(mThemeResId, true /* force */); + } + + @Test + public void applyStyle() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.applyStyle(mThemeResId, true /* force */); + } + } + @Test + public void rebase() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + destTheme.applyStyle(mThemeResId, true /* force */); + destTheme.applyStyle(android.R.style.Theme_Material, true /* force */); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.rebase(); + } + } + + @Test + public void setToSameAssetManager() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.setTo(mTheme); + } + } + + @Test + public void setToDifferentAssetManager() throws Exception { + // Create a new Resources object with the same asset paths but a different AssetManager + PackageManager packageManager = mContext.getApplicationContext().getPackageManager(); + ApplicationInfo ai = packageManager.getApplicationInfo(mContext.getPackageName(), + UserHandle.myUserId()); + + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + Configuration c = resourcesManager.getConfiguration(); + c.orientation = (c.orientation == Configuration.ORIENTATION_PORTRAIT) + ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + + Resources destResources = resourcesManager.getResources(null, ai.sourceDir, + ai.splitSourceDirs, ai.resourceDirs, ai.sharedLibraryFiles, Display.DEFAULT_DISPLAY, + c, mContext.getResources().getCompatibilityInfo(), null); + Assert.assertNotEquals(destResources.getAssets(), mContext.getAssets()); + + Resources.Theme destTheme = destResources.newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.setTo(mTheme); + } } @Test @@ -51,5 +113,4 @@ public class ResourcesThemePerfTest { mTheme.obtainStyledAttributes(android.R.style.Theme_Material, android.R.styleable.View); } } - -} +}
\ No newline at end of file diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java new file mode 100644 index 000000000000..a433d801acaf --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.perftests.utils; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.pm.PackageInstaller; +import android.content.res.Resources; +import android.util.Log; + +import org.junit.Assert; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Installs packages included within the assets directory. + */ +public class TestPackageInstaller { + private static final String LOG_TAG = "TestPackageInstaller"; + private static final String BROADCAST_ACTION = + "com.android.perftests.core.ACTION_INSTALL_COMMIT"; + + private final Context mContext; + public TestPackageInstaller(Context context) { + mContext = context; + } + + + + /** + * Installs an APK located at the specified path in the assets directory. + **/ + public InstalledPackage installPackage(String resourceName) throws IOException, + InterruptedException { + Log.d(LOG_TAG, "Installing resource APK '" + resourceName + "'"); + LocalBroadcastReceiver intentSender = new LocalBroadcastReceiver(mContext); + + // Initialize the package install session. + PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); + PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( + PackageInstaller.SessionParams.MODE_FULL_INSTALL); + params.setInstallAsInstantApp(false); + int sessionId = packageInstaller.createSession(params); + PackageInstaller.Session session = packageInstaller.openSession(sessionId); + + // Copy the apk to the install session. + try (OutputStream os = session.openWrite("TestPackageInstaller", 0, -1); + InputStream is = mContext.getResources().getAssets().openNonAsset(resourceName)) { + if (is == null) { + throw new IOException("Resource " + resourceName + " not found"); + } + byte[] buffer = new byte[4096]; + int n; + while ((n = is.read(buffer)) >= 0) { + os.write(buffer, 0, n); + } + } + + session.commit(intentSender.getIntentSender(sessionId)); + session.close(); + + // Retrieve the results of the installation. + Intent intent = intentSender.getIntentSenderResult(); + int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + Assert.assertEquals(PackageInstaller.STATUS_SUCCESS, status); + String packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME); + return new InstalledPackage(sessionId, packageName); + } + + public class InstalledPackage { + private int mSessionId; + private String mPackageName; + + private InstalledPackage(int sessionId, String packageName) { + mSessionId = sessionId; + mPackageName = packageName; + } + + public String getPackageName() { + return mPackageName; + } + + public void uninstall() throws Exception { + Log.d(LOG_TAG, "Uninstalling package '" + mPackageName + "'"); + LocalBroadcastReceiver intentSender = new LocalBroadcastReceiver(mContext); + PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); + packageInstaller.uninstall(mPackageName, intentSender.getIntentSender(mSessionId)); + int status = intentSender.getIntentSenderResult() + .getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); + Assert.assertEquals(PackageInstaller.STATUS_SUCCESS, status); + } + } + + private class LocalBroadcastReceiver extends BroadcastReceiver { + private final BlockingQueue<Intent> mIntentSenderResults = new LinkedBlockingQueue<>(); + private final Context mContext; + + private LocalBroadcastReceiver(Context context) { + mContext = context; + } + + @Override + public void onReceive(Context context, Intent intent) { + mIntentSenderResults.add(intent); + } + + IntentSender getIntentSender(int sessionId) { + String action = BROADCAST_ACTION + "." + sessionId; + IntentFilter filter = new IntentFilter(action); + mContext.registerReceiver(this, filter); + + Intent intent = new Intent(action); + PendingIntent pending = PendingIntent.getBroadcast(mContext, sessionId, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + return pending.getIntentSender(); + } + + Intent getIntentSenderResult() throws InterruptedException { + return mIntentSenderResults.take(); + } + } +} diff --git a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java index a807eb1d3311..5b1405628b49 100644 --- a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java @@ -36,7 +36,7 @@ public class DeviceIdleFrameworkInitializer { SystemServiceRegistry.registerCachedService( Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class, (context, b) -> new DeviceIdleManager( - context.getOuterContext(), IDeviceIdleController.Stub.asInterface(b))); + context, IDeviceIdleController.Stub.asInterface(b))); PowerManager.setIsIgnoringBatteryOptimizationsCallback((packageName) -> { // No need for synchronization on sIDeviceIdleController; worst case // we just initialize it twice. diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java new file mode 100644 index 000000000000..3cfb08082ff7 --- /dev/null +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -0,0 +1,112 @@ +package com.android.server.usage; + +import android.app.usage.AppStandbyInfo; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager.StandbyBuckets; +import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; +import android.content.Context; +import android.os.Looper; + +import com.android.internal.util.IndentingPrintWriter; + +import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Set; + +public interface AppStandbyInternal { + /** + * TODO AppStandbyController should probably be a binder service, and then we shouldn't need + * this method. + */ + static AppStandbyInternal newAppStandbyController(ClassLoader loader, Context context, + Looper looper) { + try { + final Class<?> clazz = Class.forName("com.android.server.usage.AppStandbyController", + true, loader); + final Constructor<?> ctor = clazz.getConstructor(Context.class, Looper.class); + return (AppStandbyInternal) ctor.newInstance(context, looper); + } catch (NoSuchMethodException | InstantiationException + | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) { + throw new RuntimeException("Unable to instantiate AppStandbyController!", e); + } + } + + void onBootPhase(int phase); + + boolean isParoledOrCharging(); + + void postCheckIdleStates(int userId); + + /** + * We send a different message to check idle states once, otherwise we would end up + * scheduling a series of repeating checkIdleStates each time we fired off one. + */ + void postOneTimeCheckIdleStates(); + + void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId); + + void setLastJobRunTime(String packageName, int userId, long elapsedRealtime); + + long getTimeSinceLastJobRun(String packageName, int userId); + + void onUserRemoved(int userId); + + void addListener(AppIdleStateChangeListener listener); + + void removeListener(AppIdleStateChangeListener listener); + + int getAppId(String packageName); + + boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, + boolean shouldObfuscateInstantApps); + + /** + * Checks if an app has been idle for a while and filters out apps that are excluded. + * It returns false if the current system state allows all apps to be considered active. + * This happens if the device is plugged in or temporarily allowed to make exceptions. + * Called by interface impls. + */ + boolean isAppIdleFiltered(String packageName, int appId, int userId, + long elapsedRealtime); + + int[] getIdleUidsForUser(int userId); + + void setAppIdleAsync(String packageName, boolean idle, int userId); + + @StandbyBuckets + int getAppStandbyBucket(String packageName, int userId, + long elapsedRealtime, boolean shouldObfuscateInstantApps); + + List<AppStandbyInfo> getAppStandbyBuckets(int userId); + + void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, + int reason, long elapsedRealtime, boolean resetTimeout); + + void addActiveDeviceAdmin(String adminPkg, int userId); + + void setActiveAdminApps(Set<String> adminPkgs, int userId); + + void onAdminDataAvailable(); + + void clearCarrierPrivilegedApps(); + + void flushToDisk(int userId); + + void flushDurationsToDisk(); + + void initializeDefaultsForSystemApps(int userId); + + void postReportContentProviderUsage(String name, String packageName, int userId); + + void postReportSyncScheduled(String packageName, int userId, boolean exempted); + + void postReportExemptedSyncStart(String packageName, int userId); + + void dumpUser(IndentingPrintWriter idpw, int userId, String pkg); + + void dumpState(String[] args, PrintWriter pw); + + boolean isAppIdleEnabled(); +} diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 1e4861a89694..1e4861a89694 100644 --- a/services/usage/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 75e8fb5a34fe..df5d6aeb8ee5 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -120,9 +120,9 @@ import java.util.concurrent.CountDownLatch; * Manages the standby state of an app, listening to various events. * * Unit test: - atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java + atest com.android.server.usage.AppStandbyControllerTests */ -public class AppStandbyController { +public class AppStandbyController implements AppStandbyInternal { private static final String TAG = "AppStandbyController"; static final boolean DEBUG = false; @@ -247,7 +247,7 @@ public class AppStandbyController { /** The length of time phone must be charging before considered stable enough to run jobs */ long mStableChargingThresholdMillis; - volatile boolean mAppIdleEnabled; + private volatile boolean mAppIdleEnabled; boolean mAppIdleTempParoled; boolean mCharging; boolean mChargingStable; @@ -320,7 +320,7 @@ public class AppStandbyController { } } - AppStandbyController(Context context, Looper looper) { + public AppStandbyController(Context context, Looper looper) { this(new Injector(context, looper)); } @@ -351,6 +351,7 @@ public class AppStandbyController { null, mHandler); } + @VisibleForTesting void setAppIdleEnabled(boolean enabled) { synchronized (mAppIdleLock) { if (mAppIdleEnabled != enabled) { @@ -363,6 +364,12 @@ public class AppStandbyController { } } + @Override + public boolean isAppIdleEnabled() { + return mAppIdleEnabled; + } + + @Override public void onBootPhase(int phase) { mInjector.onBootPhase(phase); if (phase == PHASE_SYSTEM_SERVICES_READY) { @@ -400,7 +407,7 @@ public class AppStandbyController { } } - void reportContentProviderUsage(String authority, String providerPkgName, int userId) { + private void reportContentProviderUsage(String authority, String providerPkgName, int userId) { if (!mAppIdleEnabled) return; // Get sync adapters for the authority @@ -432,7 +439,7 @@ public class AppStandbyController { } } - void reportExemptedSyncScheduled(String packageName, int userId) { + private void reportExemptedSyncScheduled(String packageName, int userId) { if (!mAppIdleEnabled) return; final int bucketToPromote; @@ -463,7 +470,7 @@ public class AppStandbyController { } } - void reportUnexemptedSyncScheduled(String packageName, int userId) { + private void reportUnexemptedSyncScheduled(String packageName, int userId) { if (!mAppIdleEnabled) return; final long elapsedRealtime = mInjector.elapsedRealtime(); @@ -482,7 +489,7 @@ public class AppStandbyController { } } - void reportExemptedSyncStart(String packageName, int userId) { + private void reportExemptedSyncStart(String packageName, int userId) { if (!mAppIdleEnabled) return; final long elapsedRealtime = mInjector.elapsedRealtime(); @@ -497,6 +504,7 @@ public class AppStandbyController { } } + @VisibleForTesting void setChargingState(boolean charging) { synchronized (mAppIdleLock) { if (mCharging != charging) { @@ -517,7 +525,7 @@ public class AppStandbyController { } } - void updateChargingStableState() { + private void updateChargingStableState() { synchronized (mAppIdleLock) { if (mChargingStable != mCharging) { if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging); @@ -527,8 +535,7 @@ public class AppStandbyController { } } - /** Paroled here means temporary pardon from being inactive */ - void setAppIdleParoled(boolean paroled) { + private void setAppIdleParoled(boolean paroled) { synchronized (mAppIdleLock) { final long now = mInjector.currentTimeMillis(); if (mAppIdleTempParoled != paroled) { @@ -545,7 +552,8 @@ public class AppStandbyController { } } - boolean isParoledOrCharging() { + @Override + public boolean isParoledOrCharging() { if (!mAppIdleEnabled) return true; synchronized (mAppIdleLock) { // Only consider stable charging when determining charge state. @@ -583,15 +591,13 @@ public class AppStandbyController { mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED); } - void postCheckIdleStates(int userId) { + @Override + public void postCheckIdleStates(int userId) { mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); } - /** - * We send a different message to check idle states once, otherwise we would end up - * scheduling a series of repeating checkIdleStates each time we fired off one. - */ - void postOneTimeCheckIdleStates() { + @Override + public void postOneTimeCheckIdleStates() { if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { // Not booted yet; wait for it! mPendingOneTimeCheckIdleStates = true; @@ -601,10 +607,7 @@ public class AppStandbyController { } } - /** - * Check all running users' or specified user's apps to see if they enter an idle state. - * @return Returns whether checking should continue periodically. - */ + @VisibleForTesting boolean checkIdleStates(int checkUserId) { if (!mAppIdleEnabled) { return false; @@ -776,19 +779,15 @@ public class AppStandbyController { * @return the bucket for the app, based on time since last used */ @GuardedBy("mAppIdleLock") - @StandbyBuckets int getBucketForLocked(String packageName, int userId, + @StandbyBuckets + private int getBucketForLocked(String packageName, int userId, long elapsedRealtime) { int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId, elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds); return THRESHOLD_BUCKETS[bucketIndex]; } - /** - * Check if it's been a while since last parole and let idle apps do some work. - * If network is not available, delay parole until it is available up until the end of the - * parole window. Force the parole to be set if end of the parole window is reached. - */ - void checkParoleTimeout() { + private void checkParoleTimeout() { boolean setParoled = false; boolean waitForNetwork = false; NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo(); @@ -845,7 +844,7 @@ public class AppStandbyController { } } - void onDeviceIdleModeChanged() { + private void onDeviceIdleModeChanged() { final boolean deviceIdle = mPowerManager.isDeviceIdleMode(); if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle); boolean paroled = false; @@ -869,7 +868,8 @@ public class AppStandbyController { setAppIdleParoled(paroled); } - void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) { + @Override + public void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) { if (!mAppIdleEnabled) return; synchronized (mAppIdleLock) { // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back @@ -950,14 +950,7 @@ public class AppStandbyController { } } - /** - * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle, - * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind - * the threshold for idle. - * - * This method is always called from the handler thread, so not much synchronization is - * required. - */ + @VisibleForTesting void forceIdleState(String packageName, int userId, boolean idle) { if (!mAppIdleEnabled) return; @@ -983,12 +976,14 @@ public class AppStandbyController { } } + @Override public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) { synchronized (mAppIdleLock) { mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime); } } + @Override public long getTimeSinceLastJobRun(String packageName, int userId) { final long elapsedRealtime = mInjector.elapsedRealtime(); synchronized (mAppIdleLock) { @@ -996,6 +991,7 @@ public class AppStandbyController { } } + @Override public void onUserRemoved(int userId) { synchronized (mAppIdleLock) { mAppIdleHistory.onUserRemoved(userId); @@ -1011,7 +1007,8 @@ public class AppStandbyController { } } - void addListener(AppIdleStateChangeListener listener) { + @Override + public void addListener(AppIdleStateChangeListener listener) { synchronized (mPackageAccessListeners) { if (!mPackageAccessListeners.contains(listener)) { mPackageAccessListeners.add(listener); @@ -1019,13 +1016,15 @@ public class AppStandbyController { } } - void removeListener(AppIdleStateChangeListener listener) { + @Override + public void removeListener(AppIdleStateChangeListener listener) { synchronized (mPackageAccessListeners) { mPackageAccessListeners.remove(listener); } } - int getAppId(String packageName) { + @Override + public int getAppId(String packageName) { try { ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName, PackageManager.MATCH_ANY_USER @@ -1036,7 +1035,8 @@ public class AppStandbyController { } } - boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, + @Override + public boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps) { if (isParoledOrCharging()) { return false; @@ -1048,8 +1048,7 @@ public class AppStandbyController { return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime); } - /** Returns true if this app should be whitelisted for some reason, to never go into standby */ - boolean isAppSpecial(String packageName, int appId, int userId) { + private boolean isAppSpecial(String packageName, int appId, int userId) { if (packageName == null) return false; // If not enabled at all, of course nobody is ever idle. if (!mAppIdleEnabled) { @@ -1102,13 +1101,8 @@ public class AppStandbyController { return false; } - /** - * Checks if an app has been idle for a while and filters out apps that are excluded. - * It returns false if the current system state allows all apps to be considered active. - * This happens if the device is plugged in or temporarily allowed to make exceptions. - * Called by interface impls. - */ - boolean isAppIdleFiltered(String packageName, int appId, int userId, + @Override + public boolean isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime) { if (isAppSpecial(packageName, appId, userId)) { return false; @@ -1117,7 +1111,8 @@ public class AppStandbyController { } } - int[] getIdleUidsForUser(int userId) { + @Override + public int[] getIdleUidsForUser(int userId) { if (!mAppIdleEnabled) { return new int[0]; } @@ -1181,13 +1176,15 @@ public class AppStandbyController { return res; } - void setAppIdleAsync(String packageName, boolean idle, int userId) { + @Override + public void setAppIdleAsync(String packageName, boolean idle, int userId) { if (packageName == null || !mAppIdleEnabled) return; mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName) .sendToTarget(); } + @Override @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps) { if (!mAppIdleEnabled || (shouldObfuscateInstantApps @@ -1200,18 +1197,21 @@ public class AppStandbyController { } } + @Override public List<AppStandbyInfo> getAppStandbyBuckets(int userId) { synchronized (mAppIdleLock) { return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled); } } + @VisibleForTesting void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime) { setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false); } - void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, + @Override + public void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout) { synchronized (mAppIdleLock) { // If the package is not installed, don't allow the bucket to be set. @@ -1279,6 +1279,7 @@ public class AppStandbyController { } } + @Override public void addActiveDeviceAdmin(String adminPkg, int userId) { synchronized (mActiveAdminApps) { Set<String> adminPkgs = mActiveAdminApps.get(userId); @@ -1290,6 +1291,7 @@ public class AppStandbyController { } } + @Override public void setActiveAdminApps(Set<String> adminPkgs, int userId) { synchronized (mActiveAdminApps) { if (adminPkgs == null) { @@ -1300,6 +1302,7 @@ public class AppStandbyController { } } + @Override public void onAdminDataAvailable() { mAdminDataAvailableLatch.countDown(); } @@ -1314,6 +1317,7 @@ public class AppStandbyController { } } + @VisibleForTesting Set<String> getActiveAdminAppsForTest(int userId) { synchronized (mActiveAdminApps) { return mActiveAdminApps.get(userId); @@ -1342,7 +1346,8 @@ public class AppStandbyController { } } - void clearCarrierPrivilegedApps() { + @Override + public void clearCarrierPrivilegedApps() { if (DEBUG) { Slog.i(TAG, "Clearing carrier privileged apps list"); } @@ -1368,7 +1373,7 @@ public class AppStandbyController { return packageName != null && packageName.equals(activeScorer); } - void informListeners(String packageName, int userId, int bucket, int reason, + private void informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction) { final boolean idle = bucket >= STANDBY_BUCKET_RARE; synchronized (mPackageAccessListeners) { @@ -1381,7 +1386,7 @@ public class AppStandbyController { } } - void informParoleStateChanged() { + private void informParoleStateChanged() { final boolean paroled = isParoledOrCharging(); synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { @@ -1390,13 +1395,15 @@ public class AppStandbyController { } } - void flushToDisk(int userId) { + @Override + public void flushToDisk(int userId) { synchronized (mAppIdleLock) { mAppIdleHistory.writeAppIdleTimes(userId); } } - void flushDurationsToDisk() { + @Override + public void flushDurationsToDisk() { // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be // considered not-idle, which is the safest outcome in such an event. synchronized (mAppIdleLock) { @@ -1404,10 +1411,11 @@ public class AppStandbyController { } } - boolean isDisplayOn() { + private boolean isDisplayOn() { return mInjector.isDefaultDisplayOn(); } + @VisibleForTesting void clearAppIdleForPackage(String packageName, int userId) { synchronized (mAppIdleLock) { mAppIdleHistory.clearUsage(packageName, userId); @@ -1431,7 +1439,8 @@ public class AppStandbyController { } } - void initializeDefaultsForSystemApps(int userId) { + @Override + public void initializeDefaultsForSystemApps(int userId) { if (!mSystemServicesReady) { // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled mPendingInitializeDefaults = true; @@ -1461,7 +1470,8 @@ public class AppStandbyController { } } - void postReportContentProviderUsage(String name, String packageName, int userId) { + @Override + public void postReportContentProviderUsage(String name, String packageName, int userId) { SomeArgs args = SomeArgs.obtain(); args.arg1 = name; args.arg2 = packageName; @@ -1470,23 +1480,27 @@ public class AppStandbyController { .sendToTarget(); } - void postReportSyncScheduled(String packageName, int userId, boolean exempted) { + @Override + public void postReportSyncScheduled(String packageName, int userId, boolean exempted) { mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName) .sendToTarget(); } - void postReportExemptedSyncStart(String packageName, int userId) { + @Override + public void postReportExemptedSyncStart(String packageName, int userId) { mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName) .sendToTarget(); } - void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) { + @Override + public void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) { synchronized (mAppIdleLock) { mAppIdleHistory.dump(idpw, userId, pkg); } } - void dumpState(String[] args, PrintWriter pw) { + @Override + public void dumpState(String[] args, PrintWriter pw) { synchronized (mAppIdleLock) { pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps + "): " + mCarrierPrivilegedApps); diff --git a/api/current.txt b/api/current.txt index 3ce043c89b65..a123f2cc8ba2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2834,6 +2834,7 @@ package android.accessibilityservice { method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo(); method @NonNull public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController(); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); + method @NonNull public final android.util.SparseArray<java.util.List<android.view.accessibility.AccessibilityWindowInfo>> getWindowsOnAllDisplays(); method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent); method public final android.os.IBinder onBind(android.content.Intent); method @Deprecated protected boolean onGesture(int); @@ -6363,6 +6364,7 @@ package android.app { method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); + method @NonNull public android.util.SparseArray<java.util.List<android.view.accessibility.AccessibilityWindowInfo>> getWindowsOnAllDisplays(); method public void grantRuntimePermission(String, String); method public void grantRuntimePermissionAsUser(String, String, android.os.UserHandle); method public boolean injectInputEvent(android.view.InputEvent, boolean); @@ -57410,7 +57412,7 @@ package android.widget { method public boolean onPrivateIMECommand(String, android.os.Bundle); method public void onRestoreInstanceState(android.os.Parcelable); method public android.os.Parcelable onSaveInstanceState(); - method protected void onSelectionChanged(int, int); + method @CallSuper protected void onSelectionChanged(int, int); method protected void onTextChanged(CharSequence, int, int, int); method public boolean onTextContextMenuItem(int); method public void removeTextChangedListener(android.text.TextWatcher); diff --git a/api/system-current.txt b/api/system-current.txt index a4e20cc5c500..8875e7995105 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24,6 +24,7 @@ package android { field public static final String BACKUP = "android.permission.BACKUP"; field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE"; field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"; + field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE"; field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE"; field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE"; field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"; @@ -6361,6 +6362,7 @@ package android.service.autofill { method public android.os.IBinder onBind(android.content.Intent); method @Nullable public float[][] onCalculateScores(@NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @Nullable String, @Nullable android.os.Bundle, @Nullable java.util.Map, @Nullable java.util.Map); method @Deprecated @Nullable public float[][] onGetScores(@Nullable String, @Nullable android.os.Bundle, @NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>); + field public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE"; field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService"; @@ -7303,6 +7305,14 @@ package android.telephony { method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int); } + public abstract class CellBroadcastService extends android.app.Service { + ctor public CellBroadcastService(); + method @CallSuper public android.os.IBinder onBind(android.content.Intent); + method public abstract void onCdmaCellBroadcastSms(int, byte[]); + method public abstract void onGsmCellBroadcastSms(int, byte[]); + field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; + } + public final class DataFailCause { field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab field public static final int ACCESS_BLOCK = 2087; // 0x827 diff --git a/api/test-current.txt b/api/test-current.txt index a40cb923065f..7637b87085b8 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5,6 +5,7 @@ package android { field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS"; field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING"; field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS"; + field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE"; field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE"; field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA"; @@ -2404,7 +2405,6 @@ package android.provider { field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis"; field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis"; field public static final String NOTIFICATION_BADGING = "notification_badging"; - field @Deprecated public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; field public static final String USER_SETUP_COMPLETE = "user_setup_complete"; field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; @@ -2481,6 +2481,7 @@ package android.service.autofill { public abstract class AutofillFieldClassificationService extends android.app.Service { ctor public AutofillFieldClassificationService(); method public android.os.IBinder onBind(android.content.Intent); + field public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE"; field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService"; @@ -2900,6 +2901,8 @@ package android.telephony { } public class PhoneStateListener { + method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber); + method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber); field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER = 268435456; // 0x10000000 field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER = 536870912; // 0x20000000 } diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING index c1cba5f7f22d..56f5cc034f05 100644 --- a/cmds/locksettings/TEST_MAPPING +++ b/cmds/locksettings/TEST_MAPPING @@ -1,5 +1,5 @@ { - "presubmit": [ + "presubmit-devicepolicy": [ { "name": "CtsDevicePolicyManagerTestCases", "options": [ diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 42132ee0daae..7d446a9a1ed6 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -53,6 +53,8 @@ void sigHandler(int sig) { if (gStatsService != nullptr) { gStatsService->Terminate(); } + ALOGW("statsd terminated on receiving signal %d.", sig); + exit(1); } void registerSigHandler() diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 76ee9a6e5996..460b9e0995c8 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -1199,87 +1199,66 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi ConfigKey cfgKey1(uid, 12341); long timeBase1 = 1; - sp<StatsLogProcessor> processor = + sp<StatsLogProcessor> processor1 = CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1); // Metric 1 is not active. // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_EQ(1, processor->mMetricsManagers.size()); - auto it = processor->mMetricsManagers.find(cfgKey1); - EXPECT_TRUE(it != processor->mMetricsManagers.end()); + EXPECT_EQ(1, processor1->mMetricsManagers.size()); + auto it = processor1->mMetricsManagers.find(cfgKey1); + EXPECT_TRUE(it != processor1->mMetricsManagers.end()); auto& metricsManager1 = it->second; EXPECT_TRUE(metricsManager1->isActive()); - auto metricIt = metricsManager1->mAllMetricProducers.begin(); - for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId1) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); - auto& metricProducer1 = *metricIt; - EXPECT_FALSE(metricProducer1->isActive()); - - metricIt = metricsManager1->mAllMetricProducers.begin(); - for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId2) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end()); - auto& metricProducer2 = *metricIt; - EXPECT_TRUE(metricProducer2->isActive()); - - int i = 0; - for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { - if (metricsManager1->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger1->atom_matcher_id()) { - break; - } - } - const auto& activation1 = metricProducer1->mEventActivationMap.at(i); - EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns); - EXPECT_EQ(0, activation1->start_ns); - EXPECT_EQ(kNotActive, activation1->state); - EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType); - - i = 0; - for (; i < metricsManager1->mAllAtomMatchers.size(); i++) { - if (metricsManager1->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger2->atom_matcher_id()) { - break; - } - } - const auto& activation2 = metricProducer1->mEventActivationMap.at(i); - EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns); - EXPECT_EQ(0, activation2->start_ns); - EXPECT_EQ(kNotActive, activation2->state); - EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType); + EXPECT_EQ(metricsManager1->mAllMetricProducers.size(), 2); + // We assume that the index of a MetricProducer within the mAllMetricProducers + // array follows the order in which metrics are added to the config. + auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1); + EXPECT_FALSE(metricProducer1_1->isActive()); // inactive due to associated MetricActivation + + auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1]; + EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2); + EXPECT_TRUE(metricProducer1_2->isActive()); + + EXPECT_EQ(metricProducer1_1->mEventActivationMap.size(), 2); + // The key in mEventActivationMap is the index of the associated atom matcher. We assume + // that matchers are indexed in the order that they are added to the config. + const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0); + EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns); + EXPECT_EQ(0, activation1_1_1->start_ns); + EXPECT_EQ(kNotActive, activation1_1_1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType); + + const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1); + EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns); + EXPECT_EQ(0, activation1_1_2->start_ns); + EXPECT_EQ(kNotActive, activation1_1_2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType); // }}}------------------------------------------------------------------------------ // Trigger Activation 1 for Metric 1 std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")}; auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1); - processor->OnLogEvent(event.get()); + processor1->OnLogEvent(event.get()); // Metric 1 is not active; Activation 1 set to kActiveOnBoot // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_FALSE(metricProducer1->isActive()); - EXPECT_EQ(0, activation1->start_ns); - EXPECT_EQ(kActiveOnBoot, activation1->state); - EXPECT_EQ(0, activation2->start_ns); - EXPECT_EQ(kNotActive, activation2->state); + EXPECT_FALSE(metricProducer1_1->isActive()); + EXPECT_EQ(0, activation1_1_1->start_ns); + EXPECT_EQ(kActiveOnBoot, activation1_1_1->state); + EXPECT_EQ(0, activation1_1_2->start_ns); + EXPECT_EQ(kNotActive, activation1_1_2->state); - EXPECT_TRUE(metricProducer2->isActive()); + EXPECT_TRUE(metricProducer1_2->isActive()); // }}}----------------------------------------------------------------------------- // Simulate shutdown by saving state to disk int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC; - processor->SaveActiveConfigsToDisk(shutDownTime); - EXPECT_FALSE(metricProducer1->isActive()); - int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC; + processor1->SaveActiveConfigsToDisk(shutDownTime); + EXPECT_FALSE(metricProducer1_1->isActive()); // Simulate device restarted state by creating new instance of StatsLogProcessor with the // same config. @@ -1293,55 +1272,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi EXPECT_EQ(1, processor2->mMetricsManagers.size()); it = processor2->mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor2->mMetricsManagers.end()); - auto& metricsManager1001 = it->second; - EXPECT_TRUE(metricsManager1001->isActive()); - - metricIt = metricsManager1001->mAllMetricProducers.begin(); - for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId1) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); - auto& metricProducer1001 = *metricIt; - EXPECT_FALSE(metricProducer1001->isActive()); - - metricIt = metricsManager1001->mAllMetricProducers.begin(); - for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId2) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end()); - auto& metricProducer1002 = *metricIt; - EXPECT_TRUE(metricProducer1002->isActive()); - - i = 0; - for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { - if (metricsManager1001->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger1->atom_matcher_id()) { - break; - } - } - const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i); - EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns); - EXPECT_EQ(0, activation1001_1->start_ns); - EXPECT_EQ(kNotActive, activation1001_1->state); - EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001_1->activationType); - - i = 0; - for (; i < metricsManager1001->mAllAtomMatchers.size(); i++) { - if (metricsManager1001->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger2->atom_matcher_id()) { - break; - } - } + auto& metricsManager2 = it->second; + EXPECT_TRUE(metricsManager2->isActive()); - const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i); - EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns); - EXPECT_EQ(0, activation1001_2->start_ns); - EXPECT_EQ(kNotActive, activation1001_2->state); - EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1001_2->activationType); + EXPECT_EQ(metricsManager2->mAllMetricProducers.size(), 2); + // We assume that the index of a MetricProducer within the mAllMetricProducers + // array follows the order in which metrics are added to the config. + auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1); + EXPECT_FALSE(metricProducer2_1->isActive()); + + auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1]; + EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2); + EXPECT_TRUE(metricProducer2_2->isActive()); + + EXPECT_EQ(metricProducer2_1->mEventActivationMap.size(), 2); + // The key in mEventActivationMap is the index of the associated atom matcher. We assume + // that matchers are indexed in the order that they are added to the config. + const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0); + EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns); + EXPECT_EQ(0, activation2_1_1->start_ns); + EXPECT_EQ(kNotActive, activation2_1_1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType); + + const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1); + EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns); + EXPECT_EQ(0, activation2_1_2->start_ns); + EXPECT_EQ(kNotActive, activation2_1_2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType); // }}}----------------------------------------------------------------------------------- // Load saved state from disk. @@ -1350,13 +1308,14 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi // Metric 1 active; Activation 1 is active, Activation 2 is not active // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_TRUE(metricProducer1001->isActive()); - EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); - EXPECT_EQ(kActive, activation1001_1->state); - EXPECT_EQ(0, activation1001_2->start_ns); - EXPECT_EQ(kNotActive, activation1001_2->state); + EXPECT_TRUE(metricProducer2_1->isActive()); + int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC; + EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns); + EXPECT_EQ(kActive, activation2_1_1->state); + EXPECT_EQ(0, activation2_1_2->start_ns); + EXPECT_EQ(kNotActive, activation2_1_2->state); - EXPECT_TRUE(metricProducer1002->isActive()); + EXPECT_TRUE(metricProducer2_2->isActive()); // }}}-------------------------------------------------------------------------------- // Trigger Activation 2 for Metric 1. @@ -1369,23 +1328,23 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi // Metric 1 active; Activation 1 is active, Activation 2 is active // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_TRUE(metricProducer1001->isActive()); - EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns); - EXPECT_EQ(kActive, activation1001_1->state); - EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation1001_2->start_ns); - EXPECT_EQ(kActive, activation1001_2->state); + EXPECT_TRUE(metricProducer2_1->isActive()); + EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns); + EXPECT_EQ(kActive, activation2_1_1->state); + EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns); + EXPECT_EQ(kActive, activation2_1_2->state); - EXPECT_TRUE(metricProducer1002->isActive()); + EXPECT_TRUE(metricProducer2_2->isActive()); // }}}--------------------------------------------------------------------------- // Simulate shutdown by saving state to disk shutDownTime = timeBase2 + 50 * NS_PER_SEC; processor2->SaveActiveConfigsToDisk(shutDownTime); - EXPECT_TRUE(metricProducer1001->isActive()); - EXPECT_TRUE(metricProducer1002->isActive()); - ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime; - int64_t ttl2 = screenOnEvent->GetElapsedTimestampNs() + - metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime; + EXPECT_TRUE(metricProducer2_1->isActive()); + EXPECT_TRUE(metricProducer2_2->isActive()); + ttl1 -= shutDownTime - timeBase2; + int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC + - (shutDownTime - screenOnEvent->GetElapsedTimestampNs()); // Simulate device restarted state by creating new instance of StatsLogProcessor with the // same config. @@ -1399,55 +1358,34 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi EXPECT_EQ(1, processor3->mMetricsManagers.size()); it = processor3->mMetricsManagers.find(cfgKey1); EXPECT_TRUE(it != processor3->mMetricsManagers.end()); - auto& metricsManagerTimeBase3 = it->second; - EXPECT_TRUE(metricsManagerTimeBase3->isActive()); - - metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); - for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId1) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); - auto& metricProducerTimeBase3_1 = *metricIt; - EXPECT_FALSE(metricProducerTimeBase3_1->isActive()); - - metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin(); - for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) { - if ((*metricIt)->getMetricId() == metricId2) { - break; - } - } - EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end()); - auto& metricProducerTimeBase3_2 = *metricIt; - EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); - - i = 0; - for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger1->atom_matcher_id()) { - break; - } - } - const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i); - EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns); - EXPECT_EQ(0, activationTimeBase3_1->start_ns); - EXPECT_EQ(kNotActive, activationTimeBase3_1->state); - EXPECT_EQ(ACTIVATE_ON_BOOT, activationTimeBase3_1->activationType); - - i = 0; - for (; i < metricsManagerTimeBase3->mAllAtomMatchers.size(); i++) { - if (metricsManagerTimeBase3->mAllAtomMatchers[i]->getId() == - metric1ActivationTrigger2->atom_matcher_id()) { - break; - } - } + auto& metricsManager3 = it->second; + EXPECT_TRUE(metricsManager3->isActive()); - const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i); - EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns); - EXPECT_EQ(0, activationTimeBase3_2->start_ns); - EXPECT_EQ(kNotActive, activationTimeBase3_2->state); - EXPECT_EQ(ACTIVATE_IMMEDIATELY, activationTimeBase3_2->activationType); + EXPECT_EQ(metricsManager3->mAllMetricProducers.size(), 2); + // We assume that the index of a MetricProducer within the mAllMetricProducers + // array follows the order in which metrics are added to the config. + auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0]; + EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1); + EXPECT_FALSE(metricProducer3_1->isActive()); + + auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1]; + EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2); + EXPECT_TRUE(metricProducer3_2->isActive()); + + EXPECT_EQ(metricProducer3_1->mEventActivationMap.size(), 2); + // The key in mEventActivationMap is the index of the associated atom matcher. We assume + // that matchers are indexed in the order that they are added to the config. + const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0); + EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns); + EXPECT_EQ(0, activation3_1_1->start_ns); + EXPECT_EQ(kNotActive, activation3_1_1->state); + EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType); + + const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1); + EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns); + EXPECT_EQ(0, activation3_1_2->start_ns); + EXPECT_EQ(kNotActive, activation3_1_2->state); + EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType); // }}}---------------------------------------------------------------------------------- // Load saved state from disk. @@ -1456,13 +1394,13 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi // Metric 1 active: Activation 1 is active, Activation 2 is active // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); - EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns); - EXPECT_EQ(kActive, activationTimeBase3_1->state); - EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns); - EXPECT_EQ(kActive, activationTimeBase3_2->state); + EXPECT_TRUE(metricProducer3_1->isActive()); + EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns); + EXPECT_EQ(kActive, activation3_1_1->state); + EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns); + EXPECT_EQ(kActive, activation3_1_2->state); - EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + EXPECT_TRUE(metricProducer3_2->isActive()); // }}}------------------------------------------------------------------------------- @@ -1473,15 +1411,16 @@ TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActi ); processor3->OnLogEvent(screenOnEvent.get()); - // Metric 1 active; Activation 1 is not active, Activation 2 is set to active + // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire), + // Activation 2 is set to active // Metric 2 is active. // {{{--------------------------------------------------------------------------- - EXPECT_TRUE(metricProducerTimeBase3_1->isActive()); - EXPECT_EQ(kNotActive, activationTimeBase3_1->state); - EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activationTimeBase3_2->start_ns); - EXPECT_EQ(kActive, activationTimeBase3_2->state); + EXPECT_TRUE(metricProducer3_1->isActive()); + EXPECT_EQ(kNotActive, activation3_1_1->state); + EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns); + EXPECT_EQ(kActive, activation3_1_2->state); - EXPECT_TRUE(metricProducerTimeBase3_2->isActive()); + EXPECT_TRUE(metricProducer3_2->isActive()); // }}}--------------------------------------------------------------------------- } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index d3c274f4bdfe..4603f08c765f 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -605,7 +605,7 @@ public abstract class AccessibilityService extends Service { } /** - * Gets the windows on the screen. This method returns only the windows + * Gets the windows on the screen of the default display. This method returns only the windows * that a sighted user can interact with, as opposed to all windows. * For example, if there is a modal dialog shown and the user cannot touch * anything behind it, then only the modal window will be reported @@ -632,6 +632,34 @@ public abstract class AccessibilityService extends Service { } /** + * Gets the windows on the screen of all displays. This method returns only the windows + * that a sighted user can interact with, as opposed to all windows. + * For example, if there is a modal dialog shown and the user cannot touch + * anything behind it, then only the modal window will be reported + * (assuming it is the top one). For convenience the returned windows + * are ordered in a descending layer order, which is the windows that + * are on top are reported first. Since the user can always + * interact with the window that has input focus by typing, the focused + * window is always returned (even if covered by a modal window). + * <p> + * <strong>Note:</strong> In order to access the windows your service has + * to declare the capability to retrieve window content by setting the + * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} + * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. + * Also the service has to opt-in to retrieve the interactive windows by + * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} + * flag. + * </p> + * + * @return The windows of all displays if there are windows and the service is can retrieve + * them, otherwise an empty list. The key of SparseArray is display ID. + */ + @NonNull + public final SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { + return AccessibilityInteractionClient.getInstance().getWindowsOnAllDisplays(mConnectionId); + } + + /** * Gets the root node in the currently active window if this service * can retrieve window content. The active window is the one that the user * is currently touching or the window with input focus, if the user is not diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 1ca07dd6ed23..4841781170e1 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -60,7 +60,7 @@ interface IAccessibilityServiceConnection { AccessibilityWindowInfo getWindow(int windowId); - List<AccessibilityWindowInfo> getWindows(); + AccessibilityWindowInfo.WindowListSparseArray getWindows(); AccessibilityServiceInfo getServiceInfo(); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 40cb29fc80ab..cb9ebac728ec 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -20,6 +20,7 @@ import static android.app.ActivityThread.DEBUG_CONFIGURATION; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -191,6 +192,17 @@ public class ResourcesManager { } } Log.i(TAG, "Invalidated " + count + " asset managers that referenced " + path); + + for (int i = mCachedApkAssets.size() - 1; i >= 0; i--) { + final ApkKey key = mCachedApkAssets.keyAt(i); + if (key.path.equals(path)) { + WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.remove(key); + if (apkAssetsRef != null && apkAssetsRef.get() != null) { + apkAssetsRef.get().close(); + } + mCachedApkAssets.remove(key); + } + } } } @@ -1000,6 +1012,14 @@ public class ResourcesManager { } } + @TestApi + public final boolean applyConfigurationToResources(@NonNull Configuration config, + @Nullable CompatibilityInfo compat) { + synchronized(this) { + return applyConfigurationToResourcesLocked(config, compat); + } + } + public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { try { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 049933743450..e81dc1c59040 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1343,13 +1343,13 @@ public final class SystemServiceRegistry { * @hide */ public static <T> void registerCachedService(String serviceName, Class<T> serviceWrapperClass, - BiFunction<ContextImpl, IBinder, T> serviceFetcher) { + BiFunction<Context, IBinder, T> serviceFetcher) { registerService(serviceName, serviceWrapperClass, new CachedServiceFetcher<T>() { @Override public T createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(serviceName); - return serviceFetcher.apply(ctx, b); + return serviceFetcher.apply(ctx.getOuterContext(), b); }}); } diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index fd93450c29f0..13d566c0e04b 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -42,6 +42,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; +import android.util.SparseArray; import android.view.Display; import android.view.InputEvent; import android.view.KeyEvent; @@ -535,7 +536,7 @@ public final class UiAutomation { } /** - * Gets the windows on the screen. This method returns only the windows + * Gets the windows on the screen of the default display. This method returns only the windows * that a sighted user can interact with, as opposed to all windows. * For example, if there is a modal dialog shown and the user cannot touch * anything behind it, then only the modal window will be reported @@ -562,6 +563,35 @@ public final class UiAutomation { } /** + * Gets the windows on the screen of all displays. This method returns only the windows + * that a sighted user can interact with, as opposed to all windows. + * For example, if there is a modal dialog shown and the user cannot touch + * anything behind it, then only the modal window will be reported + * (assuming it is the top one). For convenience the returned windows + * are ordered in a descending layer order, which is the windows that + * are higher in the Z-order are reported first. + * <p> + * <strong>Note:</strong> In order to access the windows you have to opt-in + * to retrieve the interactive windows by setting the + * {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag. + * </p> + * + * @return The windows of all displays if there are windows and the service is can retrieve + * them, otherwise an empty list. The key of SparseArray is display ID. + */ + @NonNull + public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { + final int connectionId; + synchronized (mLock) { + throwIfNotConnectedLocked(); + connectionId = mConnectionId; + } + // Calling out without a lock held. + return AccessibilityInteractionClient.getInstance() + .getWindowsOnAllDisplays(connectionId); + } + + /** * Gets the root {@link AccessibilityNodeInfo} in the active window. * * @return The root info. diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl index d8cea2860aa8..6d790b381ace 100644 --- a/core/java/android/app/role/IRoleManager.aidl +++ b/core/java/android/app/role/IRoleManager.aidl @@ -19,7 +19,6 @@ package android.app.role; import android.app.role.IOnRoleHoldersChangedListener; import android.os.Bundle; import android.os.RemoteCallback; -import android.telephony.IFinancialSmsCallback; /** * @hide @@ -55,9 +54,4 @@ interface IRoleManager { List<String> getHeldRolesFromController(in String packageName); String getDefaultSmsPackage(int userId); - - /** - * Get filtered SMS messages for financial app. - */ - void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback); } diff --git a/core/java/android/app/usage/AppStandbyInfo.java b/core/java/android/app/usage/AppStandbyInfo.java index ebdbf833b81a..c283702a6bbf 100644 --- a/core/java/android/app/usage/AppStandbyInfo.java +++ b/core/java/android/app/usage/AppStandbyInfo.java @@ -22,6 +22,10 @@ import android.os.Parcelable; /** * A pair of {package, bucket} to denote the app standby bucket for a given package. * Used as a vehicle of data across the binder IPC. + * + * Note we're not moving this class to the jobscheduler apex, because it's consumed by + * UsageStatsManager, which is not updatable anyway, so making this updatable isn't really + * beneficial. * @hide */ public final class AppStandbyInfo implements Parcelable { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 802c1a0ae6d5..08817e05e0a5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3301,7 +3301,7 @@ public abstract class Context { * <dt> {@link #VIBRATOR_SERVICE} ("vibrator") * <dd> A {@link android.os.Vibrator} for interacting with the vibrator * hardware. - * <dt> {@link #CONNECTIVITY_SERVICE} ("connection") + * <dt> {@link #CONNECTIVITY_SERVICE} ("connectivity") * <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for * handling management of network connections. * <dt> {@link #IPSEC_SERVICE} ("ipsec") diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java index e24512ac525d..c3daad188792 100644 --- a/core/java/android/content/PermissionChecker.java +++ b/core/java/android/content/PermissionChecker.java @@ -16,8 +16,6 @@ package android.content; -import static android.app.AppOpsManager.strOpToOp; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -52,6 +50,19 @@ import java.lang.annotation.RetentionPolicy; * permission model for which the user had disabled the "permission" * which is achieved by disallowing the corresponding app op. * </p> + * <p> + * This class has two types of methods and you should be careful which + * type to call based on whether permission protected data is being + * passed to the app or you are just checking whether the app holds a + * permission. The reason is that a permission check requires checking + * the runtime permission and if it is granted checking the corresponding + * app op as for apps not supporting the runtime mode we never revoke + * permissions but disable app ops. Since there are two types of app op + * checks, one that does not leave a record an action was performed and + * another the does, one needs to call the preflight flavor of the checks + * named xxxForPreflight only if no private data is being delivered but + * a permission check is what is needed and the xxxForDataDelivery where + * the permission check is right before private data delivery. * * @hide */ @@ -65,6 +76,9 @@ public final class PermissionChecker { /** Permission result: The permission is denied because the app op is not allowed. */ public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1; + /** Constant when the PID for which we check permissions is unknown. */ + public static final int PID_UNKNOWN = -1; + /** @hide */ @IntDef({PERMISSION_GRANTED, PERMISSION_DENIED, @@ -77,63 +91,97 @@ public final class PermissionChecker { } /** - * @deprecated Use {@link #checkPermission(Context, String, int, int, String, String)} instead + * Checks whether a given package in a UID and PID has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * point where you will deliver the permission protected data to clients. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} + * to determine if the app has or may have location permission (if app has only foreground + * location the grant state depends on the app's fg/gb state) and this check will not + * leave a trace that permission protected data was delivered. When you are about to + * deliver the location data to a registered listener you should use this method which + * will evaluate the permission access based on the current fg/bg state of the app and + * leave a record that the data was accessed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID + * is not known. + * @param uid The uid for which to check. + * @param packageName The package name for which to check. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * @param message A message describing the reason the permission was checked + * + * @see #checkPermissionForPreflight(Context, String, int, int, String) */ - @Deprecated @PermissionResult - public static int checkPermission(@NonNull Context context, @NonNull String permission, - int pid, int uid, @Nullable String packageName) { - return checkPermission(context, permission, pid, uid, packageName, null); + public static int checkPermissionForDataDelivery(@NonNull Context context, + @NonNull String permission, int pid, int uid, @Nullable String packageName, + @Nullable String message) { + return checkPermissionCommon(context, permission, pid, uid, packageName, message, + true /*forDataDelivery*/); } /** * Checks whether a given package in a UID and PID has a given permission * and whether the app op that corresponds to this permission is allowed. * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * preflight point where you will not deliver the permission protected data + * to clients but schedule permission data delivery, apps register listeners, + * etc. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use this method to determine if the app has or may have location + * permission (if app has only foreground location the grant state depends on the app's + * fg/gb state) and this check will not leave a trace that permission protected data + * was delivered. When you are about to deliver the location data to a registered + * listener you should use {@link #checkPermissionForDataDelivery(Context, String, + * int, int, String, String)} which will evaluate the permission access based on the current + * fg/bg state of the app and leave a record that the data was accessed. + * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. * @param uid The uid for which to check. * @param packageName The package name for which to check. If null the * the first package for the calling UID will be used. - * @param message A message describing the reason the permission was checked - * * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * + * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String) */ @PermissionResult - public static int checkPermission(@NonNull Context context, @NonNull String permission, - int pid, int uid, @Nullable String packageName, @Nullable String message) { - if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { - return PERMISSION_DENIED; - } - - AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); - String op = appOpsManager.permissionToOp(permission); - if (op == null) { - return PERMISSION_GRANTED; - } - - if (packageName == null) { - String[] packageNames = context.getPackageManager().getPackagesForUid(uid); - if (packageNames == null || packageNames.length <= 0) { - return PERMISSION_DENIED; - } - packageName = packageNames[0]; - } - - if (appOpsManager.noteProxyOpNoThrow(strOpToOp(op), packageName, uid, message) - != AppOpsManager.MODE_ALLOWED) { - return PERMISSION_DENIED_APP_OP; - } - - return PERMISSION_GRANTED; + public static int checkPermissionForPreflight(@NonNull Context context, + @NonNull String permission, int pid, int uid, @Nullable String packageName) { + return checkPermissionCommon(context, permission, pid, uid, packageName, null /*message*/, + false /*forDataDelivery*/); } /** * Checks whether your app has a given permission and whether the app op * that corresponds to this permission is allowed. * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * point where you will deliver the permission protected data to clients. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use {@link #checkSelfPermissionForPreflight(Context, String)} + * to determine if the app has or may have location permission (if app has only foreground + * location the grant state depends on the app's fg/gb state) and this check will not + * leave a trace that permission protected data was delivered. When you are about to + * deliver the location data to a registered listener you should use this method + * which will evaluate the permission access based on the current fg/bg state of the + * app and leave a record that the data was accessed. + * * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as * {@link Process#myUid()}. * @@ -141,74 +189,229 @@ public final class PermissionChecker { * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * @param message A message describing the reason the permission was checked + * + * @see #checkSelfPermissionForPreflight(Context, String) */ @PermissionResult - public static int checkSelfPermission(@NonNull Context context, - @NonNull String permission) { - return checkPermission(context, permission, Process.myPid(), - Process.myUid(), context.getPackageName(), null /* self access */); + public static int checkSelfPermissionForDataDelivery(@NonNull Context context, + @NonNull String permission, @Nullable String message) { + return checkPermissionForDataDelivery(context, permission, Process.myPid(), + Process.myUid(), context.getPackageName(), message); } /** - * @deprecated Use {@link #checkCallingPermission(Context, String, String, String)} instead + * Checks whether your app has a given permission and whether the app op + * that corresponds to this permission is allowed. + * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * preflight point where you will not deliver the permission protected data + * to clients but schedule permission data delivery, apps register listeners, + * etc. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use this method to determine if the app has or may have location + * permission (if app has only foreground location the grant state depends on the + * app's fg/gb state) and this check will not leave a trace that permission protected + * data was delivered. When you are about to deliver the location data to a registered + * listener you should use this method which will evaluate the permission access based + * on the current fg/bg state of the app and leave a record that the data was accessed. + * + * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as + * {@link Process#myUid()}. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * + * @see #checkSelfPermissionForDataDelivery(Context, String, String) */ - @Deprecated @PermissionResult - public static int checkCallingPermission(@NonNull Context context, - @NonNull String permission, @Nullable String packageName) { - return checkCallingPermission(context, permission, packageName, null); + public static int checkSelfPermissionForPreflight(@NonNull Context context, + @NonNull String permission) { + return checkPermissionForPreflight(context, permission, Process.myPid(), + Process.myUid(), context.getPackageName()); } /** * Checks whether the IPC you are handling has a given permission and whether * the app op that corresponds to this permission is allowed. * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * point where you will deliver the permission protected data to clients. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use {@link #checkCallingPermissionForPreflight(Context, String, String)} + * to determine if the app has or may have location permission (if app has only foreground + * location the grant state depends on the app's fg/gb state) and this check will not + * leave a trace that permission protected data was delivered. When you are about to + * deliver the location data to a registered listener you should use this method which + * will evaluate the permission access based on the current fg/bg state of the app and + * leave a record that the data was accessed. + * * @param context Context for accessing resources. * @param permission The permission to check. * @param packageName The package name making the IPC. If null the * the first package for the calling UID will be used. - * @param message A message describing the reason the permission was checked - * * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * @param message A message describing the reason the permission was checked + * + * @see #checkCallingPermissionForPreflight(Context, String, String) */ @PermissionResult - public static int checkCallingPermission(@NonNull Context context, + public static int checkCallingPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, @Nullable String packageName, @Nullable String message) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_DENIED; } - return checkPermission(context, permission, Binder.getCallingPid(), + return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName, message); } /** - * @deprecated Use {@link #checkCallingOrSelfPermission(Context, String, String)} instead + * Checks whether the IPC you are handling has a given permission and whether + * the app op that corresponds to this permission is allowed. + * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * preflight point where you will not deliver the permission protected data + * to clients but schedule permission data delivery, apps register listeners, + * etc. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use this method to determine if the app has or may have location + * permission (if app has only foreground location the grant state depends on the app's + * fg/gb state) and this check will not leave a trace that permission protected data + * was delivered. When you are about to deliver the location data to a registered + * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, + * String, String)} which will evaluate the permission access based on the current fg/bg state + * of the app and leave a record that the data was accessed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param packageName The package name making the IPC. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * + * @see #checkCallingPermissionForDataDelivery(Context, String, String, String) */ - @Deprecated @PermissionResult - public static int checkCallingOrSelfPermission(@NonNull Context context, - @NonNull String permission) { - return checkCallingOrSelfPermission(context, permission, null); + public static int checkCallingPermissionForPreflight(@NonNull Context context, + @NonNull String permission, @Nullable String packageName) { + if (Binder.getCallingPid() == Process.myPid()) { + return PERMISSION_DENIED; + } + return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); } /** * Checks whether the IPC you are handling or your app has a given permission * and whether the app op that corresponds to this permission is allowed. * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * point where you will deliver the permission protected data to clients. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use {@link #checkCallingOrSelfPermissionForPreflight(Context, String)} + * to determine if the app has or may have location permission (if app has only foreground + * location the grant state depends on the app's fg/gb state) and this check will not + * leave a trace that permission protected data was delivered. When you are about to + * deliver the location data to a registered listener you should use this method which + * will evaluate the permission access based on the current fg/bg state of the app and + * leave a record that the data was accessed. + * * @param context Context for accessing resources. * @param permission The permission to check. - * @param message A message describing the reason the permission was checked - * * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * @param message A message describing the reason the permission was checked + * + * @see #checkCallingOrSelfPermissionForPreflight(Context, String) */ @PermissionResult - public static int checkCallingOrSelfPermission(@NonNull Context context, + public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, @Nullable String message) { String packageName = (Binder.getCallingPid() == Process.myPid()) ? context.getPackageName() : null; - return checkPermission(context, permission, Binder.getCallingPid(), + return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName, message); } -} + + /** + * Checks whether the IPC you are handling or your app has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * <strong>NOTE:</strong> Use this method only for permission checks at the + * preflight point where you will not deliver the permission protected data + * to clients but schedule permission data delivery, apps register listeners, + * etc. + * + * <p>For example, if an app registers a location listener it should have the location + * permission but no data is actually sent to the app at the moment of registration + * and you should use this method to determine if the app has or may have location + * permission (if app has only foreground location the grant state depends on the + * app's fg/gb state) and this check will not leave a trace that permission protected + * data was delivered. When you are about to deliver the location data to a registered + * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, + * String, String)} which will evaluate the permission access based on the current fg/bg state + * of the app and leave a record that the data was accessed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + * + * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String) + */ + @PermissionResult + public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context, + @NonNull String permission) { + String packageName = (Binder.getCallingPid() == Process.myPid()) + ? context.getPackageName() : null; + return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); + } + + private static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, + int pid, int uid, @Nullable String packageName, @Nullable String message, + boolean forDataDelivery) { + if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { + return PERMISSION_DENIED; + } + + AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + String op = appOpsManager.permissionToOp(permission); + if (op == null) { + return PERMISSION_GRANTED; + } + + if (packageName == null) { + String[] packageNames = context.getPackageManager().getPackagesForUid(uid); + if (packageNames == null || packageNames.length <= 0) { + return PERMISSION_DENIED; + } + packageName = packageNames[0]; + } + + if (forDataDelivery) { + if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, message) + != AppOpsManager.MODE_ALLOWED) { + return PERMISSION_DENIED_APP_OP; + } + } else { + final int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); + if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_FOREGROUND) { + return PERMISSION_DENIED_APP_OP; + } + } + + return PERMISSION_GRANTED; + } +}
\ No newline at end of file diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl index 43a4fe5bc414..3d7e3befd9f1 100644 --- a/core/java/android/content/om/IOverlayManager.aidl +++ b/core/java/android/content/om/IOverlayManager.aidl @@ -157,4 +157,10 @@ interface IOverlayManager { * Returns the list of default overlay packages, or an empty array if there are none. */ String[] getDefaultOverlayPackages(); + + /** + * Invalidates and removes the idmap for an overlay, + * @param packageName The name of the overlay package whose idmap should be deleted. + */ + void invalidateCachesForOverlay(in String packageName, in int userIs); } diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index f2716fedc186..853e8189ea8a 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; @@ -163,4 +164,28 @@ public class OverlayManager { throw e.rethrowFromSystemServer(); } } + + /** + * Returns information about all overlays for the given target package for + * the specified user. The returned list is ordered according to the + * overlay priority with the highest priority at the end of the list. + * + * @param targetPackageName The name of the target package. + * @param user The user to get the OverlayInfos for. + * + * @hide + */ + @TestApi + @RequiresPermission(anyOf = { + "android.permission.INTERACT_ACROSS_USERS", + }) + @NonNull + public void invalidateCachesForOverlay(@NonNull final String targetPackageName, + @NonNull UserHandle user) { + try { + mService.invalidateCachesForOverlay(targetPackageName, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 0a99142a9fbd..9f0bade9bd29 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -420,10 +420,10 @@ public class UserInfo implements Parcelable { lastLoggedInTime = source.readLong(); lastLoggedInFingerprint = source.readString(); partial = source.readBoolean(); + preCreated = source.readBoolean(); profileGroupId = source.readInt(); guestToRemove = source.readBoolean(); restrictedProfileParentId = source.readInt(); profileBadge = source.readInt(); - preCreated = source.readBoolean(); } } diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 69462ab99483..a35ad567ed81 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -188,7 +188,7 @@ public final class ApkAssets { /** * Closes this class and the contained {@link #mStringBlock}. */ - public void close() throws Throwable { + public void close() { synchronized (this) { if (mOpen) { mOpen = false; diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index b7bc8229fa45..2ae1932c3437 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -175,7 +175,7 @@ final class StringBlock { } } - public void close() throws Throwable { + public void close() { synchronized (this) { if (mOpen) { mOpen = false; diff --git a/core/java/android/hardware/location/ContextHubClientCallback.java b/core/java/android/hardware/location/ContextHubClientCallback.java index cc2fe65dcb7e..20fa7538e2d5 100644 --- a/core/java/android/hardware/location/ContextHubClientCallback.java +++ b/core/java/android/hardware/location/ContextHubClientCallback.java @@ -66,7 +66,9 @@ public class ContextHubClientCallback { public void onNanoAppAborted(ContextHubClient client, long nanoAppId, int abortCode) {} /** - * Callback invoked when a nanoapp is loaded at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically loaded at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. This callback is not invoked for a + * nanoapp that is loaded internally by CHRE (e.g. nanoapps that are preloaded by the system). * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been loaded @@ -74,7 +76,8 @@ public class ContextHubClientCallback { public void onNanoAppLoaded(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is unloaded from the attached Context Hub. + * Callback invoked when a nanoapp is dynamically unloaded from the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been unloaded @@ -82,7 +85,8 @@ public class ContextHubClientCallback { public void onNanoAppUnloaded(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is enabled at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically enabled at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been enabled @@ -90,7 +94,8 @@ public class ContextHubClientCallback { public void onNanoAppEnabled(ContextHubClient client, long nanoAppId) {} /** - * Callback invoked when a nanoapp is disabled at the attached Context Hub. + * Callback invoked when a nanoapp is dynamically disabled at the attached Context Hub through + * the {@link android.hardware.location.ContextHubManager}. * * @param client the client that is associated with this callback * @param nanoAppId the ID of the nanoapp that had been disabled diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3c26df3c560b..e4e8bf791d47 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7908,16 +7908,6 @@ public final class Settings { public static final String NOTIFICATION_BADGING = "notification_badging"; /** - * Whether the notification bubbles are globally enabled - * The value is boolean (1 or 0). - * @hide - * @deprecated use {@link Global#NOTIFICATION_BUBBLES} instead. - */ - @TestApi - @Deprecated - public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; - - /** * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right * swipe). * diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index 320dcec675cc..28842a7fa1d7 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -93,6 +93,13 @@ public abstract class AutofillFieldClassificationService extends Service { */ public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH"; + /** + * Field classification algorithm that compares a credit card string to known last four digits. + * + * <p>Service implementation must provide this algorithm.</p> + */ + public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD"; + /** {@hide} **/ public static final String EXTRA_SCORES = "scores"; diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 70dfef574ca5..dfc5c8217fda 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -170,13 +170,23 @@ public abstract class RecognitionService extends Service { * Checks whether the caller has sufficient permissions * * @param listener to send the error message to in case of error + * @param forDataDelivery If the permission check is for delivering the sensitive data. * @return {@code true} if the caller has enough permissions, {@code false} otherwise */ - private boolean checkPermissions(IRecognitionListener listener) { + private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery) { if (DBG) Log.d(TAG, "checkPermissions"); - if (PermissionChecker.checkCallingOrSelfPermission(this, - android.Manifest.permission.RECORD_AUDIO) == PermissionChecker.PERMISSION_GRANTED) { - return true; + if (forDataDelivery) { + if (PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(this, + android.Manifest.permission.RECORD_AUDIO, null /*message*/) + == PermissionChecker.PERMISSION_GRANTED) { + return true; + } + } else { + if (PermissionChecker.checkCallingOrSelfPermissionForPreflight(this, + android.Manifest.permission.RECORD_AUDIO) + == PermissionChecker.PERMISSION_GRANTED) { + return true; + } } try { Log.e(TAG, "call for recognition service without RECORD_AUDIO permissions"); @@ -342,7 +352,7 @@ public abstract class RecognitionService extends Service { public void startListening(Intent recognizerIntent, IRecognitionListener listener) { if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder()); final RecognitionService service = mServiceRef.get(); - if (service != null && service.checkPermissions(listener)) { + if (service != null && service.checkPermissions(listener, true /*forDataDelivery*/)) { service.mHandler.sendMessage(Message.obtain(service.mHandler, MSG_START_LISTENING, service.new StartListeningArgs( recognizerIntent, listener, Binder.getCallingUid()))); @@ -353,7 +363,7 @@ public abstract class RecognitionService extends Service { public void stopListening(IRecognitionListener listener) { if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder()); final RecognitionService service = mServiceRef.get(); - if (service != null && service.checkPermissions(listener)) { + if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) { service.mHandler.sendMessage(Message.obtain(service.mHandler, MSG_STOP_LISTENING, listener)); } @@ -363,7 +373,7 @@ public abstract class RecognitionService extends Service { public void cancel(IRecognitionListener listener) { if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder()); final RecognitionService service = mServiceRef.get(); - if (service != null && service.checkPermissions(listener)) { + if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) { service.mHandler.sendMessage(Message.obtain(service.mHandler, MSG_CANCEL, listener)); } diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index d9fa9f24f1ae..bb10ef10d79e 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -259,23 +259,38 @@ public final class AccessibilityInteractionClient } /** - * Gets the info for all windows. + * Gets the info for all windows of the default display. * * @param connectionId The id of a connection for interacting with the system. * @return The {@link AccessibilityWindowInfo} list. */ public List<AccessibilityWindowInfo> getWindows(int connectionId) { + final SparseArray<List<AccessibilityWindowInfo>> windows = + getWindowsOnAllDisplays(connectionId); + if (windows.size() > 0) { + return windows.valueAt(Display.DEFAULT_DISPLAY); + } + return Collections.emptyList(); + } + + /** + * Gets the info for all windows of all displays. + * + * @param connectionId The id of a connection for interacting with the system. + * @return The SparseArray of {@link AccessibilityWindowInfo} list. + * The key of SparseArray is display ID. + */ + public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays(int connectionId) { try { IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { - SparseArray<List<AccessibilityWindowInfo>> allWindows = + SparseArray<List<AccessibilityWindowInfo>> windows = sAccessibilityCache.getWindowsOnAllDisplays(); - List<AccessibilityWindowInfo> windows; - if (allWindows != null) { + if (windows != null) { if (DEBUG) { Log.i(LOG_TAG, "Windows cache hit"); } - return allWindows.valueAt(Display.DEFAULT_DISPLAY); + return windows; } if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); @@ -287,9 +302,7 @@ public final class AccessibilityInteractionClient Binder.restoreCallingIdentity(identityToken); } if (windows != null) { - allWindows = new SparseArray<>(); - allWindows.put(Display.DEFAULT_DISPLAY, windows); - sAccessibilityCache.setWindowsOnAllDisplays(allWindows); + sAccessibilityCache.setWindowsOnAllDisplays(windows); return windows; } } else { @@ -298,9 +311,11 @@ public final class AccessibilityInteractionClient } } } catch (RemoteException re) { - Log.e(LOG_TAG, "Error while calling remote getWindows", re); + Log.e(LOG_TAG, "Error while calling remote getWindowsOnAllDisplays", re); } - return Collections.emptyList(); + + final SparseArray<List<AccessibilityWindowInfo>> emptyWindows = new SparseArray<>(); + return emptyWindows; } /** diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.aidl b/core/java/android/view/accessibility/AccessibilityWindowInfo.aidl index fdb25fb1ee61..c36c4aa5b00a 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.aidl +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.aidl @@ -17,3 +17,4 @@ package android.view.accessibility; parcelable AccessibilityWindowInfo; +parcelable AccessibilityWindowInfo.WindowListSparseArray; diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index 6a3af3478449..5fa8a6e0e06b 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -26,9 +26,12 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.LongArray; import android.util.Pools.SynchronizedPool; +import android.util.SparseArray; import android.view.Display; import android.view.accessibility.AccessibilityEvent.WindowsChangeTypes; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; @@ -797,4 +800,49 @@ public final class AccessibilityWindowInfo implements Parcelable { return new AccessibilityWindowInfo[size]; } }; + + /** + * Transfers a sparsearray with lists having {@link AccessibilityWindowInfo}s across an IPC. + * The key of this sparsearray is display Id. + * + * @hide + */ + public static final class WindowListSparseArray + extends SparseArray<List<AccessibilityWindowInfo>> implements Parcelable { + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + final int count = size(); + dest.writeInt(count); + for (int i = 0; i < count; i++) { + dest.writeParcelableList(valueAt(i), 0); + dest.writeInt(keyAt(i)); + } + } + + public static final Parcelable.Creator<WindowListSparseArray> CREATOR = + new Parcelable.Creator<WindowListSparseArray>() { + public WindowListSparseArray createFromParcel( + Parcel source) { + final WindowListSparseArray array = new WindowListSparseArray(); + final ClassLoader loader = array.getClass().getClassLoader(); + final int count = source.readInt(); + for (int i = 0; i < count; i++) { + List<AccessibilityWindowInfo> windows = new ArrayList<>(); + source.readParcelableList(windows, loader); + array.put(source.readInt(), windows); + } + return array; + } + + public WindowListSparseArray[] newArray(int size) { + return new WindowListSparseArray[size]; + } + }; + } } diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index fc23c54e834e..358fdc78c0a0 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.Nullable; import android.text.TextUtils; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.regex.Pattern; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index f997d6878a9c..31f50555af1d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -23,6 +23,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_C import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; import android.R; +import android.annotation.CallSuper; import android.annotation.CheckResult; import android.annotation.ColorInt; import android.annotation.DrawableRes; @@ -10446,10 +10447,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * This method is called when the selection has changed, in case any * subclasses would like to know. + * </p> + * <p class="note"><strong>Note:</strong> Always call the super implementation, which informs + * the accessibility subsystem about the selection change. + * </p> * * @param selStart The new selection start location. * @param selEnd The new selection end location. */ + @CallSuper protected void onSelectionChanged(int selStart, int selEnd) { sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); } diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index e415b41459ab..4d8378a34599 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -43,11 +43,6 @@ interface IPlatformCompat /** * Reports that a compatibility change is affecting an app process now. * - * <p>Same as {@link #reportChange(long, ApplicationInfo)}, except it receives a package name - * instead of an {@link ApplicationInfo} - * object, and finds an app info object based on the package name. Returns {@code true} if - * there is no installed package by that name. - * * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)}, * you do not need to call this API directly. The change will be reported for you. * @@ -57,6 +52,17 @@ interface IPlatformCompat void reportChangeByPackageName(long changeId, in String packageName); /** + * Reports that a compatibility change is affecting an app process now. + * + * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)}, + * you do not need to call this API directly. The change will be reported for you. + * + * @param changeId The ID of the compatibility change taking effect. + * @param uid The UID of the app in question. + */ + void reportChangeByUid(long changeId, int uid); + + /** * Query if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * @@ -95,4 +101,28 @@ interface IPlatformCompat * @return {@code true} if the change is enabled for the current app. */ boolean isChangeEnabledByPackageName(long changeId, in String packageName); + + /** + * Query if a given compatibility change is enabled for an app process. This method should + * be called when implementing functionality on behalf of the affected app. + * + * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid + * instead of an {@link ApplicationInfo} object, and finds an app info object based on the + * uid (or objects if there's more than one package associated with the UID). + * Returns {@code true} if there are no installed packages for the required UID, or if the + * change is enabled for ALL of the installed packages associated with the provided UID. Please + * use a more specific API if you want a different behaviour for multi-package UIDs. + * + * <p>If this method returns {@code true}, the calling code should implement the compatibility + * change, resulting in differing behaviour compared to earlier releases. If this method + * returns {@code false}, the calling code should behave as it did in earlier releases. + * + * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is + * no need to call that method directly. + * + * @param changeId The ID of the compatibility change in question. + * @param uid The UID of the app in question. + * @return {@code true} if the change is enabled for the current app. + */ + boolean isChangeEnabledByUid(long changeId, int uid); }
\ No newline at end of file diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 5142d3cd2b99..033e9b2c6eba 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -239,6 +239,13 @@ public final class SystemUiDeviceConfigFlags { public static final String ASSIST_TRANSCRIPTION_MIN_DURATION = "assist_transcription_min_duration"; + /** + * (boolean) Whether or not to enable an extra section in the notification shade which + * filters for "people" related messages. + */ + public static final String NOTIFICATIONS_USE_PEOPLE_FILTERING = + "notifications_use_people_filtering"; + // Flags related to brightline falsing /** diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 9fff447c2478..fd3cd42b07a1 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -35,7 +35,7 @@ import com.android.server.NetworkManagementSocketTagger; import dalvik.system.RuntimeHooks; import dalvik.system.VMRuntime; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -203,13 +203,15 @@ public class RuntimeInit { public static void preForkInit() { if (DEBUG) Slog.d(TAG, "Entered preForkInit."); RuntimeInit.enableDdms(); + // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e. + // MimeMap.setDefault(DefaultMimeMapFactory.create()); /* * Replace libcore's minimal default mapping between MIME types and file * extensions with a mapping that's suitable for Android. Android's mapping * contains many more entries that are derived from IANA registrations but * with several customizations (extensions, overrides). */ - MimeMap.setDefault(DefaultMimeMapFactory.create()); + MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create); } @UnsupportedAppUsage diff --git a/core/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java index 2230c3134301..31ea5b2bf07c 100644 --- a/core/java/com/android/internal/util/MimeIconUtils.java +++ b/core/java/com/android/internal/util/MimeIconUtils.java @@ -27,7 +27,7 @@ import android.util.ArrayMap; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.Locale; import java.util.Objects; diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java b/core/java/com/android/internal/util/function/DecConsumer.java index 93c9adaac12d..0abb785bea32 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java +++ b/core/java/com/android/internal/util/function/DecConsumer.java @@ -14,16 +14,15 @@ * limitations under the License. */ -package com.android.server.integrity.engine; +package com.android.internal.util.function; + +import java.util.function.Consumer; /** - * The engine used to evaluate rules against app installs. + * A 10-argument {@link Consumer} * - * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine - * to allow/block that install. + * @hide */ -public final class RuleEvaluation { - private static final String TAG = "RuleEvaluation"; - - // TODO: Add singleton injection. +public interface DecConsumer<A, B, C, D, E, F, G, H, I, J> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); } diff --git a/core/java/com/android/internal/util/function/DecFunction.java b/core/java/com/android/internal/util/function/DecFunction.java new file mode 100644 index 000000000000..59fc5e6e6562 --- /dev/null +++ b/core/java/com/android/internal/util/function/DecFunction.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Function; + +/** + * A 10-argument {@link Function} + * + * @hide + */ +public interface DecFunction<A, B, C, D, E, F, G, H, I, J, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); +} diff --git a/core/java/com/android/internal/util/function/DecPredicate.java b/core/java/com/android/internal/util/function/DecPredicate.java new file mode 100644 index 000000000000..975993dc05dc --- /dev/null +++ b/core/java/com/android/internal/util/function/DecPredicate.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 10-argument {@link Predicate} + * + * @hide + */ +public interface DecPredicate<A, B, C, D, E, F, G, H, I, J> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j); +} diff --git a/core/java/com/android/internal/util/function/UndecConsumer.java b/core/java/com/android/internal/util/function/UndecConsumer.java new file mode 100644 index 000000000000..1a1d4ca600af --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecConsumer.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Consumer; + +/** + * A 11-argument {@link Consumer} + * + * @hide + */ +public interface UndecConsumer<A, B, C, D, E, F, G, H, I, J, K> { + void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} diff --git a/core/java/com/android/internal/util/function/UndecFunction.java b/core/java/com/android/internal/util/function/UndecFunction.java new file mode 100644 index 000000000000..5cd324c2a7e5 --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecFunction.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Function; + +/** + * A 11-argument {@link Function} + * + * @hide + */ +public interface UndecFunction<A, B, C, D, E, F, G, H, I, J, K, R> { + R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} diff --git a/core/java/com/android/internal/util/function/UndecPredicate.java b/core/java/com/android/internal/util/function/UndecPredicate.java new file mode 100644 index 000000000000..c09193eb7a11 --- /dev/null +++ b/core/java/com/android/internal/util/function/UndecPredicate.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.function; + +import java.util.function.Predicate; + +/** + * A 11-argument {@link Predicate} + * + * @hide + */ +public interface UndecPredicate<A, B, C, D, E, F, G, H, I, J, K> { + boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); +} diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java index d74e715605bb..7a17253ffd35 100755 --- a/core/java/com/android/internal/util/function/pooled/OmniFunction.java +++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java @@ -18,6 +18,8 @@ package com.android.internal.util.function.pooled; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; @@ -32,6 +34,8 @@ import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecConsumer; +import com.android.internal.util.function.UndecFunction; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -43,62 +47,65 @@ import java.util.function.Function; * * @hide */ -abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements +abstract class OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> implements PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>, QuadFunction<A, B, C, D, R>, QuintFunction<A, B, C, D, E, R>, HexFunction<A, B, C, D, E, F, R>, HeptFunction<A, B, C, D, E, F, G, R>, OctFunction<A, B, C, D, E, F, G, H, R>, NonaFunction<A, B, C, D, E, F, G, H, I, R>, + DecFunction<A, B, C, D, E, F, G, H, I, J, R>, + UndecFunction<A, B, C, D, E, F, G, H, I, J, K, R>, PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>, QuintConsumer<A, B, C, D, E>, HexConsumer<A, B, C, D, E, F>, HeptConsumer<A, B, C, D, E, F, G>, OctConsumer<A, B, C, D, E, F, G, H>, - NonaConsumer<A, B, C, D, E, F, G, H, I>, PooledPredicate<A>, BiPredicate<A, B>, - PooledSupplier<R>, PooledRunnable, ThrowingRunnable, ThrowingSupplier<R>, - PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { + NonaConsumer<A, B, C, D, E, F, G, H, I>, DecConsumer<A, B, C, D, E, F, G, H, I, J>, + UndecConsumer<A, B, C, D, E, F, G, H, I, J, K>, + PooledPredicate<A>, BiPredicate<A, B>, PooledSupplier<R>, PooledRunnable, ThrowingRunnable, + ThrowingSupplier<R>, PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble { - abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i); + abstract R invoke(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k); @Override public R apply(A o, B o2) { - return invoke(o, o2, null, null, null, null, null, null, null); + return invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public R apply(A o) { - return invoke(o, null, null, null, null, null, null, null, null); + return invoke(o, null, null, null, null, null, null, null, null, null, null); } - public abstract <V> OmniFunction<A, B, C, D, E, F, G, H, I, V> andThen( + public abstract <V> OmniFunction<A, B, C, D, E, F, G, H, I, J, K, V> andThen( Function<? super R, ? extends V> after); - public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> negate(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> negate(); @Override public void accept(A o, B o2) { - invoke(o, o2, null, null, null, null, null, null, null); + invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public void accept(A o) { - invoke(o, null, null, null, null, null, null, null, null); + invoke(o, null, null, null, null, null, null, null, null, null, null); } @Override public void run() { - invoke(null, null, null, null, null, null, null, null, null); + invoke(null, null, null, null, null, null, null, null, null, null, null); } @Override public R get() { - return invoke(null, null, null, null, null, null, null, null, null); + return invoke(null, null, null, null, null, null, null, null, null, null, null); } @Override public boolean test(A o, B o2) { - return (Boolean) invoke(o, o2, null, null, null, null, null, null, null); + return (Boolean) invoke(o, o2, null, null, null, null, null, null, null, null, null); } @Override public boolean test(A o) { - return (Boolean) invoke(o, null, null, null, null, null, null, null, null); + return (Boolean) invoke(o, null, null, null, null, null, null, null, null, null, null); } @Override @@ -113,72 +120,92 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements @Override public R apply(A a, B b, C c) { - return invoke(a, b, c, null, null, null, null, null, null); + return invoke(a, b, c, null, null, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c) { - invoke(a, b, c, null, null, null, null, null, null); + invoke(a, b, c, null, null, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d) { - return invoke(a, b, c, d, null, null, null, null, null); + return invoke(a, b, c, d, null, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e) { - return invoke(a, b, c, d, e, null, null, null, null); + return invoke(a, b, c, d, e, null, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f) { - return invoke(a, b, c, d, e, f, null, null, null); + return invoke(a, b, c, d, e, f, null, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g) { - return invoke(a, b, c, d, e, f, g, null, null); + return invoke(a, b, c, d, e, f, g, null, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g, H h) { - return invoke(a, b, c, d, e, f, g, h, null); + return invoke(a, b, c, d, e, f, g, h, null, null, null); } @Override public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i) { - return invoke(a, b, c, d, e, f, g, h, i); + return invoke(a, b, c, d, e, f, g, h, i, null, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { + return invoke(a, b, c, d, e, f, g, h, i, j, null); + } + + @Override + public R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { + return invoke(a, b, c, d, e, f, g, h, i, j, k); } @Override public void accept(A a, B b, C c, D d) { - invoke(a, b, c, d, null, null, null, null, null); + invoke(a, b, c, d, null, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e) { - invoke(a, b, c, d, e, null, null, null, null); + invoke(a, b, c, d, e, null, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f) { - invoke(a, b, c, d, e, f, null, null, null); + invoke(a, b, c, d, e, f, null, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g) { - invoke(a, b, c, d, e, f, g, null, null); + invoke(a, b, c, d, e, f, g, null, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g, H h) { - invoke(a, b, c, d, e, f, g, h, null); + invoke(a, b, c, d, e, f, g, h, null, null, null); } @Override public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i) { - invoke(a, b, c, d, e, f, g, h, i); + invoke(a, b, c, d, e, f, g, h, i, null, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { + invoke(a, b, c, d, e, f, g, h, i, j, null); + } + + @Override + public void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { + invoke(a, b, c, d, e, f, g, h, i, j, k); } @Override @@ -192,5 +219,5 @@ abstract class OmniFunction<A, B, C, D, E, F, G, H, I, R> implements } @Override - public abstract OmniFunction<A, B, C, D, E, F, G, H, I, R> recycleOnUse(); + public abstract OmniFunction<A, B, C, D, E, F, G, H, I, J, K, R> recycleOnUse(); } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java index c00932e7a8aa..b9bf9337c3d6 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -21,6 +21,8 @@ import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire import android.os.Message; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HexConsumer; @@ -35,6 +37,8 @@ import com.android.internal.util.function.QuintConsumer; import com.android.internal.util.function.QuintFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; +import com.android.internal.util.function.UndecConsumer; +import com.android.internal.util.function.UndecFunction; import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType; import java.util.function.BiConsumer; @@ -181,7 +185,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -198,7 +202,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -215,7 +219,7 @@ public interface PooledLambda { A arg1) { return acquire(PooledLambdaImpl.sPool, function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -246,7 +250,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -266,7 +270,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -284,7 +288,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -302,7 +306,7 @@ public interface PooledLambda { A arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -320,7 +324,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -338,7 +342,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -356,7 +360,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -374,7 +378,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -392,7 +396,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -410,7 +414,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2) { return acquire(PooledLambdaImpl.sPool, function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); } /** @@ -442,7 +446,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -463,7 +467,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -482,7 +486,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -501,7 +505,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -520,7 +524,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -539,7 +543,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -558,7 +562,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -577,7 +581,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -596,7 +600,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3) { return acquire(PooledLambdaImpl.sPool, function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); } /** @@ -629,7 +633,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -651,7 +655,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -671,7 +675,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -691,7 +695,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -711,7 +715,7 @@ public interface PooledLambda { ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -731,7 +735,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -751,7 +755,7 @@ public interface PooledLambda { A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -771,7 +775,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -791,7 +795,7 @@ public interface PooledLambda { A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -811,7 +815,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -831,7 +835,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) { return acquire(PooledLambdaImpl.sPool, function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); } /** @@ -865,7 +869,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -888,7 +892,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); } /** @@ -909,7 +913,7 @@ public interface PooledLambda { function, A arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); } /** @@ -945,7 +949,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -969,7 +973,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); } /** @@ -991,7 +995,7 @@ public interface PooledLambda { ? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) { return acquire(PooledLambdaImpl.sPool, function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); } /** @@ -1028,7 +1032,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1053,7 +1057,7 @@ public interface PooledLambda { ? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); } /** @@ -1077,7 +1081,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) { return acquire(PooledLambdaImpl.sPool, function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); } /** @@ -1115,7 +1119,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1142,7 +1146,7 @@ public interface PooledLambda { H arg8) { return acquire(PooledLambdaImpl.sPool, function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); } /** @@ -1167,7 +1171,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) { return acquire(PooledLambdaImpl.sPool, function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); } /** @@ -1207,7 +1211,7 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - null); + null, null, null); return Message.obtain().setCallback(callback.recycleOnUse()); } } @@ -1235,7 +1239,7 @@ public interface PooledLambda { E arg5, F arg6, G arg7, H arg8, I arg9) { return acquire(PooledLambdaImpl.sPool, function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); } /** @@ -1261,7 +1265,7 @@ public interface PooledLambda { A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) { return acquire(PooledLambdaImpl.sPool, function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); } /** @@ -1302,7 +1306,209 @@ public interface PooledLambda { synchronized (Message.sPoolSync) { PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, - arg9); + arg9, null, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) } + */ + static <A, B, C, D, E, F, G, H, I, J> PooledRunnable obtainRunnable( + DecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J> function, A arg1, B arg2, C arg3, + D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + return acquire(PooledLambdaImpl.sPool, + function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, null); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) } + */ + static <A, B, C, D, E, F, G, H, I, J, R> PooledSupplier<R> obtainSupplier( + DecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + return acquire(PooledLambdaImpl.sPool, + function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, null); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8, arg9, arg10) } when handled + */ + static <A, B, C, D, E, F, G, H, I, J> Message obtainMessage( + DecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J> function, A arg1, B arg2, C arg3, + D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8, arg9, arg10, null); + return Message.obtain().setCallback(callback.recycleOnUse()); + } + } + + /** + * {@link PooledRunnable} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link PooledRunnable}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, + * arg11) } + */ + static <A, B, C, D, E, F, G, H, I, J, K> PooledRunnable obtainRunnable( + UndecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K> function, A arg1, B arg2, + C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) { + return acquire(PooledLambdaImpl.sPool, + function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, arg11); + } + + /** + * {@link PooledSupplier} factory + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link PooledSupplier}, equivalent to lambda: + * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, + * arg11) } + */ + static <A, B, C, D, E, F, G, H, I, J, K, R> PooledSupplier<R> obtainSupplier( + UndecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K, ? extends R> function, + A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, + K arg11) { + return acquire(PooledLambdaImpl.sPool, + function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9, arg10, arg11); + } + + /** + * Factory of {@link Message}s that contain an + * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its + * {@link Message#getCallback internal callback}. + * + * The callback is equivalent to one obtainable via + * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)} + * + * Note that using this method with {@link android.os.Handler#handleMessage} + * is more efficient than the alternative of {@link android.os.Handler#post} + * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points + * when obtaining {@link Message} and {@link PooledRunnable} from pools separately + * + * You may optionally set a {@link Message#what} for the message if you want to be + * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise + * there's no need to do so + * + * @param function non-capturing lambda(typically an unbounded method reference) + * to be invoked on call + * @param arg1 parameter supplied to {@code function} on call + * @param arg2 parameter supplied to {@code function} on call + * @param arg3 parameter supplied to {@code function} on call + * @param arg4 parameter supplied to {@code function} on call + * @param arg5 parameter supplied to {@code function} on call + * @param arg6 parameter supplied to {@code function} on call + * @param arg7 parameter supplied to {@code function} on call + * @param arg8 parameter supplied to {@code function} on call + * @param arg9 parameter supplied to {@code function} on call + * @param arg10 parameter supplied to {@code function} on call + * @param arg11 parameter supplied to {@code function} on call + * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6, + * arg7, arg8, arg9, arg10, arg11) } when handled + */ + static <A, B, C, D, E, F, G, H, I, J, K> Message obtainMessage( + UndecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F, + ? super G, ? super H, ? super I, ? super J, ? super K> function, A arg1, B arg2, + C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) { + synchronized (Message.sPoolSync) { + PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool, + function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, + arg8, arg9, arg10, arg11); return Message.obtain().setCallback(callback.recycleOnUse()); } } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java index e12c031f0036..c7502ef04f1b 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -26,6 +26,9 @@ import android.util.Pools; import com.android.internal.util.ArrayUtils; import com.android.internal.util.BitUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.DecConsumer; +import com.android.internal.util.function.DecFunction; +import com.android.internal.util.function.DecPredicate; import com.android.internal.util.function.HeptConsumer; import com.android.internal.util.function.HeptFunction; import com.android.internal.util.function.HeptPredicate; @@ -47,6 +50,9 @@ import com.android.internal.util.function.QuintPredicate; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.TriPredicate; +import com.android.internal.util.function.UndecConsumer; +import com.android.internal.util.function.UndecFunction; +import com.android.internal.util.function.UndecPredicate; import java.util.Arrays; import java.util.Objects; @@ -63,12 +69,12 @@ import java.util.function.Supplier; * @hide */ final class PooledLambdaImpl<R> extends OmniFunction<Object, - Object, Object, Object, Object, Object, Object, Object, Object, R> { + Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, R> { private static final boolean DEBUG = false; private static final String LOG_TAG = "PooledLambdaImpl"; - private static final int MAX_ARGS = 9; + private static final int MAX_ARGS = 11; private static final int MAX_POOL_SIZE = 50; @@ -134,7 +140,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, /** * Bit schema: - * AAAAAAAAABCDEEEEEEFFFFFF + * AAAAAAAAAAABCDEEEEEEFFFFFF * * Where: * A - whether {@link #mArgs arg} at corresponding index was specified at @@ -171,18 +177,18 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override R invoke(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, - Object a8, Object a9) { + Object a8, Object a9, Object a10, Object a11) { checkNotRecycled(); if (DEBUG) { Log.i(LOG_TAG, this + ".invoke(" + commaSeparateFirstN( - new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9 }, + new Object[] { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 }, LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS))) + ")"); } final boolean notUsed = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4) && fillInArg(a5) && fillInArg(a6) && fillInArg(a7) && fillInArg(a8) - && fillInArg(a9); + && fillInArg(a9) && fillInArg(a10) && fillInArg(a11); int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)); if (argCount != LambdaType.MASK_ARG_COUNT) { for (int i = 0; i < argCount; i++) { @@ -410,6 +416,48 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, } } } break; + + case 10: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((DecConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((DecPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7), popArg(8), popArg(9)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((DecFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9)); + } + } + } break; + + case 11: { + switch (returnType) { + case LambdaType.ReturnType.VOID: { + ((UndecConsumer) mFunc).accept(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + return null; + } + case LambdaType.ReturnType.BOOLEAN: { + return (R) (Object) ((UndecPredicate) mFunc).test(popArg(0), + popArg(1), popArg(2), popArg(3), popArg(4), + popArg(5), popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + } + case LambdaType.ReturnType.OBJECT: { + return (R) ((UndecFunction) mFunc).apply(popArg(0), popArg(1), + popArg(2), popArg(3), popArg(4), popArg(5), + popArg(6), popArg(7), popArg(8), popArg(9), popArg(10)); + } + } + } break; } throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType)); } @@ -475,7 +523,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, */ static <E extends PooledLambda> E acquire(Pool pool, Object func, int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c, - Object d, Object e, Object f, Object g, Object h, Object i) { + Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k) { PooledLambdaImpl r = acquire(pool); if (DEBUG) { Log.i(LOG_TAG, @@ -493,6 +541,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, + ", g = " + g + ", h = " + h + ", i = " + i + + ", j = " + j + + ", k = " + k + ")"); } r.mFunc = Preconditions.checkNotNull(func); @@ -508,6 +558,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, setIfInBounds(r.mArgs, 6, g); setIfInBounds(r.mArgs, 7, h); setIfInBounds(r.mArgs, 8, i); + setIfInBounds(r.mArgs, 9, j); + setIfInBounds(r.mArgs, 10, k); return (E) r; } @@ -564,13 +616,13 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - R> negate() { + Object, Object, R> negate() { throw new UnsupportedOperationException(); } @Override public <V> OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - V> andThen(Function<? super R, ? extends V> after) { + Object, Object, V> andThen(Function<? super R, ? extends V> after) { throw new UnsupportedOperationException(); } @@ -591,7 +643,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override public OmniFunction<Object, Object, Object, Object, Object, Object, Object, Object, Object, - R> recycleOnUse() { + Object, Object, R> recycleOnUse() { if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()"); mFlags |= FLAG_RECYCLE_ON_USE; return this; @@ -683,6 +735,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, case 7: return "Hept"; case 8: return "Oct"; case 9: return "Nona"; + case 10: return "Dec"; + case 11: return "Undec"; default: return "" + argCount + "arg"; } } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index cbb74dff0e49..9445319e47ec 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -321,6 +321,9 @@ static void load_maps(int pid, stats_t* stats, bool* foundSwapPss) } else if (base::StartsWith(name, "/memfd:jit-cache")) { which_heap = HEAP_DALVIK_OTHER; sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE; + } else if (base::StartsWith(name, "/memfd:jit-zygote-cache")) { + which_heap = HEAP_DALVIK_OTHER; + sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE; } else if (base::StartsWith(name, "[anon:")) { which_heap = HEAP_UNKNOWN; if (base::StartsWith(name, "[anon:dalvik-")) { diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 8aa6f860aa61..3cefeea68406 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -191,9 +191,21 @@ jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name) return -1; } +static bool verifyGroup(JNIEnv* env, int grp) +{ + if (grp < SP_DEFAULT || grp >= SP_CNT) { + signalExceptionForError(env, EINVAL, grp); + return false; + } + return true; +} + void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp) { ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp); + if (!verifyGroup(env, grp)) { + return; + } SchedPolicy sp = (SchedPolicy) grp; int res = set_sched_policy(tid, sp); if (res != NO_ERROR) { @@ -204,6 +216,9 @@ void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint void android_os_Process_setThreadGroupAndCpuset(JNIEnv* env, jobject clazz, int tid, jint grp) { ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp); + if (!verifyGroup(env, grp)) { + return; + } SchedPolicy sp = (SchedPolicy) grp; int res = set_sched_policy(tid, sp); @@ -234,6 +249,9 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin grp = SP_FOREGROUND; isDefault = true; } + if (!verifyGroup(env, grp)) { + return; + } SchedPolicy sp = (SchedPolicy) grp; if (kDebugPolicy) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7a0d0cbe6095..7ce370ff52be 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -794,6 +794,18 @@ android:permissionFlags="hardRestricted" android:protectionLevel="dangerous" /> + <!-- @SystemApi @TestApi Allows an application to forward cell broadcast messages to the cell + broadcast module. This is required in order to bind to the cell broadcast service, and + ensures that only the system can forward messages to it. + + <p>Protection level: signature|privileged + + @hide --> + <permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE" + android:label="@string/permlab_bindCellBroadcastService" + android:description="@string/permdesc_bindCellBroadcastService" + android:protectionLevel="signature" /> + <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast messages and to register a content observer to get notifications when a cell broadcast has been received and added to the database. For diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e3337b7f9ae5..7eca699d9eca 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -433,6 +433,10 @@ --> </string-array> + <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] --> + <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastreceiver + </string> + <!-- If the mobile hotspot feature requires provisioning, a package name and class name can be provided to launch a supported application that provisions the devices. diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index b53a399f0c8a..4e327082047b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -890,6 +890,16 @@ messages. This means the app could monitor or delete messages sent to your device without showing them to you.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this.[CHAR LIMIT=NONE] --> + <string name="permlab_bindCellBroadcastService">Forward cell broadcast messages</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> + <string name="permdesc_bindCellBroadcastService">Allows the app to bind to the + cell broadcast module in order to forward cell broadcast messages + as they are received. Cell broadcast alerts are delivered in some + locations to warn you of emergency situations. Malicious apps may + interfere with the performance or operation of your device when an + emergency cell broadcast is received.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readCellBroadcasts">read cell broadcast messages</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e2f2b2c64b77..a8b534061aeb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -747,6 +747,7 @@ <java-symbol type="string" name="config_default_dns_server" /> <java-symbol type="string" name="config_ethernet_iface_regex" /> <java-symbol type="array" name="config_ethernet_interfaces" /> + <java-symbol type="string" name="cellbroadcast_default_package" /> <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index d3bf0dd7a7e8..e9d5bb135e02 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -20,7 +20,6 @@ android_test { "android.test.base", ], static_libs: ["androidx.test.rules", "truth-prebuilt"], - test_suites: ["general-tests"], sdk_version: "test_current", platform_apis: true, } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java index 682416c58c72..3586216ad421 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java @@ -23,8 +23,6 @@ import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; -import java.util.List; - /** * Stub implementation of IAccessibilityServiceConnection so each test doesn't need to implement * all of the methods @@ -73,7 +71,7 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon return null; } - public List<AccessibilityWindowInfo> getWindows() { + public AccessibilityWindowInfo.WindowListSparseArray getWindows() { return null; } diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml index 054f68ba9e5c..f1ba3f6f7859 100644 --- a/data/etc/hiddenapi-package-whitelist.xml +++ b/data/etc/hiddenapi-package-whitelist.xml @@ -53,6 +53,10 @@ Do NOT include any apps that are updatable via Play Store! <hidden-api-whitelisted-app package="com.android.providers.media" /> <hidden-api-whitelisted-app package="com.android.providers.tv" /> <hidden-api-whitelisted-app package="com.android.providers.userdictionary" /> + <!-- TODO (b/141954427): Remove networkstack --> + <hidden-api-whitelisted-app package="com.android.networkstack" /> + <!-- TODO (b/141954427): Remove wifistack --> + <hidden-api-whitelisted-app package="com.android.server.wifistack" /> <hidden-api-whitelisted-app package="com.android.smspush" /> <hidden-api-whitelisted-app package="com.android.spare_parts" /> <hidden-api-whitelisted-app package="com.android.statementservice" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 89523d6bbefb..51136b993e57 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -127,6 +127,7 @@ applications that come with the platform <permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/> <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/> <permission name="android.permission.BIND_CARRIER_SERVICES"/> + <permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/> <permission name="android.permission.BIND_IMS_SERVICE"/> <permission name="android.permission.BIND_TELEPHONY_DATA_SERVICE"/> <permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/> diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 68480ced0692..f3d68755a513 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -940,9 +940,8 @@ public class LocationManager { @Nullable LocationRequest locationRequest, @NonNull LocationListener listener, @Nullable Looper looper) { - requestLocationUpdates(locationRequest, - new LocationListenerTransport(looper == null ? new Handler() : new Handler(looper), - listener)); + Handler handler = looper == null ? new Handler() : new Handler(looper); + requestLocationUpdates(locationRequest, new HandlerExecutor(handler), listener); } /** @@ -969,7 +968,31 @@ public class LocationManager { @Nullable LocationRequest locationRequest, @NonNull @CallbackExecutor Executor executor, @NonNull LocationListener listener) { - requestLocationUpdates(locationRequest, new LocationListenerTransport(executor, listener)); + synchronized (mListeners) { + LocationListenerTransport transport = mListeners.get(listener); + if (transport != null) { + transport.unregister(); + } else { + transport = new LocationListenerTransport(listener); + mListeners.put(listener, transport); + } + transport.register(executor); + + boolean registered = false; + try { + mService.requestLocationUpdates(locationRequest, transport, null, + mContext.getPackageName()); + registered = true; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } finally { + if (!registered) { + // allow gc after exception + transport.unregister(); + mListeners.remove(listener); + } + } + } } /** @@ -1009,23 +1032,6 @@ public class LocationManager { } } - private void requestLocationUpdates(@Nullable LocationRequest request, - @NonNull LocationListenerTransport transport) { - synchronized (mListeners) { - LocationListenerTransport oldTransport = mListeners.put(transport.getKey(), transport); - if (oldTransport != null) { - oldTransport.unregisterListener(); - } - - try { - mService.requestLocationUpdates(request, transport, null, - mContext.getPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - /** * Set the last known location with a new location. * @@ -1079,7 +1085,7 @@ public class LocationManager { if (transport == null) { return; } - transport.unregisterListener(); + transport.unregister(); try { mService.removeUpdates(transport, null, mContext.getPackageName()); @@ -2237,49 +2243,45 @@ public class LocationManager { private class LocationListenerTransport extends ILocationListener.Stub { - private final Executor mExecutor; - @Nullable private volatile LocationListener mListener; + private final LocationListener mListener; + @Nullable private volatile Executor mExecutor = null; - private LocationListenerTransport(@NonNull Handler handler, - @NonNull LocationListener listener) { - Preconditions.checkArgument(handler != null, "invalid null handler"); + private LocationListenerTransport(@NonNull LocationListener listener) { Preconditions.checkArgument(listener != null, "invalid null listener"); - - mExecutor = new HandlerExecutor(handler); mListener = listener; } - private LocationListenerTransport(@NonNull Executor executor, - @NonNull LocationListener listener) { - Preconditions.checkArgument(executor != null, "invalid null executor"); - Preconditions.checkArgument(listener != null, "invalid null listener"); - - mExecutor = executor; - mListener = listener; + public LocationListener getKey() { + return mListener; } - private LocationListener getKey() { - return mListener; + public void register(@NonNull Executor executor) { + Preconditions.checkArgument(executor != null, "invalid null executor"); + mExecutor = executor; } - private void unregisterListener() { - mListener = null; + public void unregister() { + mExecutor = null; } @Override public void onLocationChanged(Location location) { + Executor currentExecutor = mExecutor; + if (currentExecutor == null) { + return; + } + try { - mExecutor.execute(() -> { + currentExecutor.execute(() -> { try { - LocationListener listener = mListener; - if (listener == null) { + if (currentExecutor != mExecutor) { return; } // we may be under the binder identity if a direct executor is used long identity = Binder.clearCallingIdentity(); try { - listener.onLocationChanged(location); + mListener.onLocationChanged(location); } finally { Binder.restoreCallingIdentity(identity); } @@ -2295,18 +2297,22 @@ public class LocationManager { @Override public void onStatusChanged(String provider, int status, Bundle extras) { + Executor currentExecutor = mExecutor; + if (currentExecutor == null) { + return; + } + try { - mExecutor.execute(() -> { + currentExecutor.execute(() -> { try { - LocationListener listener = mListener; - if (listener == null) { + if (currentExecutor != mExecutor) { return; } // we may be under the binder identity if a direct executor is used long identity = Binder.clearCallingIdentity(); try { - listener.onStatusChanged(provider, status, extras); + mListener.onStatusChanged(provider, status, extras); } finally { Binder.restoreCallingIdentity(identity); } @@ -2322,18 +2328,22 @@ public class LocationManager { @Override public void onProviderEnabled(String provider) { + Executor currentExecutor = mExecutor; + if (currentExecutor == null) { + return; + } + try { - mExecutor.execute(() -> { + currentExecutor.execute(() -> { try { - LocationListener listener = mListener; - if (listener == null) { + if (currentExecutor != mExecutor) { return; } // we may be under the binder identity if a direct executor is used long identity = Binder.clearCallingIdentity(); try { - listener.onProviderEnabled(provider); + mListener.onProviderEnabled(provider); } finally { Binder.restoreCallingIdentity(identity); } @@ -2349,18 +2359,22 @@ public class LocationManager { @Override public void onProviderDisabled(String provider) { + Executor currentExecutor = mExecutor; + if (currentExecutor == null) { + return; + } + try { - mExecutor.execute(() -> { + currentExecutor.execute(() -> { try { - LocationListener listener = mListener; - if (listener == null) { + if (currentExecutor != mExecutor) { return; } // we may be under the binder identity if a direct executor is used long identity = Binder.clearCallingIdentity(); try { - listener.onProviderDisabled(provider); + mListener.onProviderDisabled(provider); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 1b713b6ab74b..81213b943c81 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -40,6 +40,7 @@ interface IMediaRouterService { void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); + void setControlCategories(IMediaRouterClient client, in List<String> categories); // Methods for media router 2 void registerClient2(IMediaRouter2Client client, String packageName); @@ -52,7 +53,7 @@ interface IMediaRouterService { * @param route the route to be selected */ void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route); - void setControlCategories(IMediaRouter2Client client, in List<String> categories); + void setControlCategories2(IMediaRouter2Client client, in List<String> categories); void registerManager(IMediaRouter2Manager manager, String packageName); void unregisterManager(IMediaRouter2Manager manager); diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 8887c7c57ccb..09221a37cb13 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.mtp.MtpConstants; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.util.HashMap; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index d72231f40dcf..9cb78696f19b 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -49,6 +49,8 @@ import android.view.Display; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -82,6 +84,7 @@ public class MediaRouter { final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>(); + List<String> mControlCategories = Collections.emptyList(); final RouteCategory mSystemCategory; @@ -358,6 +361,18 @@ public class MediaRouter { return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); } + public void setControlCategories(Collection<String> controlCategories) { + List<String> newControlCategories = new ArrayList<>(controlCategories); + mControlCategories = newControlCategories; + if (mClient != null) { + try { + mMediaRouterService.setControlCategories(mClient, newControlCategories); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to set control categories.", ex); + } + } + } + private void updatePresentationDisplays(int changedDisplayId) { final int count = mRoutes.size(); for (int i = 0; i < count; i++) { @@ -406,6 +421,7 @@ public class MediaRouter { try { Client client = new Client(); mMediaRouterService.registerClientAsUser(client, mPackageName, userId); + mMediaRouterService.setControlCategories(client, mControlCategories); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router client.", ex); @@ -1302,6 +1318,19 @@ public class MediaRouter { sStatic.rebindAsUser(userId); } + /** + * Sets the control categories of the application. + * Routes that support at least one of the given control categories only exists and are handled + * by the media router. + * + * @hide + */ + public void setControlCategories(@NonNull Collection<String> controlCategories) { + Objects.requireNonNull(controlCategories, "control categories must not be null"); + + sStatic.setControlCategories(controlCategories); + } + static void updateRoute(final RouteInfo info) { dispatchRouteChanged(info); } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 8e29e34caa14..ed35ef6a7ac7 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -129,7 +129,7 @@ public class MediaRouter2 { Client client = new Client(); try { mMediaRouterService.registerClient2(client, mPackageName); - mMediaRouterService.setControlCategories(client, mControlCategories); + mMediaRouterService.setControlCategories2(client, mControlCategories); mClient = client; } catch (RemoteException ex) { Log.e(TAG, "Unable to register media router.", ex); @@ -188,7 +188,7 @@ public class MediaRouter2 { } if (client != null) { try { - mMediaRouterService.setControlCategories(client, newControlCategories); + mMediaRouterService.setControlCategories2(client, newControlCategories); } catch (RemoteException ex) { Log.e(TAG, "Unable to set control categories.", ex); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java index 38f0175579ad..481f4796951d 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaFileTest.java @@ -31,7 +31,7 @@ import android.mtp.MtpConstants; import androidx.test.runner.AndroidJUnit4; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java index 3abf0a4941e6..a3ed07a6dee3 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.Intent; import android.media.MediaRoute2Info; +import android.media.MediaRouter; import android.media.MediaRouter2; import android.media.MediaRouter2Manager; import android.support.test.InstrumentationRegistry; @@ -72,7 +73,8 @@ public class MediaRouterManagerTest { private Context mContext; private MediaRouter2Manager mManager; - private MediaRouter2 mRouter; + private MediaRouter mRouter; + private MediaRouter2 mRouter2; private Executor mExecutor; private String mPackageName; @@ -89,7 +91,8 @@ public class MediaRouterManagerTest { public void setUp() throws Exception { mContext = InstrumentationRegistry.getTargetContext(); mManager = MediaRouter2Manager.getInstance(mContext); - mRouter = MediaRouter2.getInstance(mContext); + mRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); + mRouter2 = MediaRouter2.getInstance(mContext); //TODO: If we need to support thread pool executors, change this to thread pool executor. mExecutor = Executors.newSingleThreadExecutor(); mPackageName = mContext.getPackageName(); @@ -131,12 +134,12 @@ public class MediaRouterManagerTest { //TODO: Figure out a more proper way to test. // (Control requests shouldn't be used in this way.) - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, mockRouterCallback); - mRouter.sendControlRequest( + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); + mRouter2.sendControlRequest( new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(), new Intent(ACTION_REMOVE_ROUTE)); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); verify(mockCallback, timeout(TIMEOUT_MS)).onRouteRemoved(argThat( (MediaRoute2Info info) -> @@ -148,15 +151,41 @@ public class MediaRouterManagerTest { * Tests if we get proper routes for application that has special control category. */ @Test + public void testControlCategoryWithMediaRouter() throws Exception { + MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); + mManager.registerCallback(mExecutor, mockCallback); + + MediaRouter.Callback mockRouterCallback = mock(MediaRouter.Callback.class); + + mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter.addCallback(MediaRouter.ROUTE_TYPE_USER, mockRouterCallback); + + verify(mockCallback, timeout(TIMEOUT_MS)) + .onRoutesChanged(argThat(routes -> routes.size() > 0)); + + Map<String, MediaRoute2Info> routes = + createRouteMap(mManager.getAvailableRoutes(mPackageName)); + + Assert.assertEquals(1, routes.size()); + Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); + + mRouter.removeCallback(mockRouterCallback); + mManager.unregisterCallback(mockCallback); + } + + /** + * Tests if we get proper routes for application that has special control category. + */ + @Test public void testControlCategory() throws Exception { MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); mManager.registerCallback(mExecutor, mockCallback); MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class); - mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); - mRouter.registerCallback(mExecutor, mockRouterCallback); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); verify(mockCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -177,15 +206,15 @@ public class MediaRouterManagerTest { public void testGetRoutes() throws Exception { MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class); - mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL); - mRouter.registerCallback(mExecutor, mockCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_SPECIAL); + mRouter2.registerCallback(mExecutor, mockCallback); verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce()) .onRoutesChanged(argThat(routes -> routes.size() > 0)); - Map<String, MediaRoute2Info> routes = createRouteMap(mRouter.getRoutes()); + Map<String, MediaRoute2Info> routes = createRouteMap(mRouter2.getRoutes()); Assert.assertEquals(1, routes.size()); Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY)); - mRouter.unregisterCallback(mockCallback); + mRouter2.unregisterCallback(mockCallback); } @Test @@ -194,8 +223,8 @@ public class MediaRouterManagerTest { MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class); mManager.registerCallback(mExecutor, managerCallback); - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, mockRouterCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, mockRouterCallback); verify(managerCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -211,7 +240,7 @@ public class MediaRouterManagerTest { .onRouteAdded(argThat(route -> route.equals(routeToSelect))); mManager.unregisterCallback(managerCallback); - mRouter.unregisterCallback(mockRouterCallback); + mRouter2.unregisterCallback(mockRouterCallback); } /** @@ -223,8 +252,8 @@ public class MediaRouterManagerTest { MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class); mManager.registerCallback(mExecutor, managerCallback); - mRouter.setControlCategories(CONTROL_CATEGORIES_ALL); - mRouter.registerCallback(mExecutor, routerCallback); + mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL); + mRouter2.registerCallback(mExecutor, routerCallback); verify(managerCallback, timeout(TIMEOUT_MS)) .onRoutesChanged(argThat(routes -> routes.size() > 0)); @@ -248,7 +277,7 @@ public class MediaRouterManagerTest { .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId()) && TextUtils.equals(routeInfo.getClientPackageName(), null))); - mRouter.unregisterCallback(routerCallback); + mRouter2.unregisterCallback(routerCallback); mManager.unregisterCallback(managerCallback); } diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java index 13039a4ab1e2..03b685df644e 100644 --- a/mime/java/android/content/type/DefaultMimeMapFactory.java +++ b/mime/java/android/content/type/DefaultMimeMapFactory.java @@ -16,7 +16,7 @@ package android.content.type; -import libcore.net.MimeMap; +import libcore.content.type.MimeMap; import java.io.BufferedReader; import java.io.IOException; diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 9a063aa7b791..5ec1baee5b14 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -29,6 +29,7 @@ import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.EnhancedEstimatesImpl; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationData; @@ -42,6 +43,8 @@ import javax.inject.Singleton; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; @Module abstract class CarSystemUIModule { @@ -94,4 +97,9 @@ abstract class CarSystemUIModule { @Binds abstract SystemUIRootComponent bindSystemUIRootComponent( CarSystemUIRootComponent systemUIRootComponent); + + @Binds + @IntoMap + @ClassKey(StatusBar.class) + public abstract SystemUI providesStatusBar(CarStatusBar statusBar); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java index a107dd793551..c205bb49228c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java @@ -15,11 +15,11 @@ */ package com.android.systemui.car; -import android.content.Context; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,8 +34,8 @@ import javax.inject.Singleton; public class CarNotificationEntryManager extends NotificationEntryManager { @Inject - public CarNotificationEntryManager(Context context) { - super(context); + public CarNotificationEntryManager(NotificationData notificationData) { + super(notificationData); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index b0ab5b49f340..d21f09ce160a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.car; +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -34,6 +36,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.os.IBinder; +import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.GestureDetector; @@ -57,36 +60,83 @@ import com.android.car.notification.NotificationClickHandlerFactory; import com.android.car.notification.NotificationDataManager; import com.android.car.notification.NotificationViewController; import com.android.car.notification.PreprocessingManager; +import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.BatteryMeterView; import com.android.systemui.CarSystemUIFactory; import com.android.systemui.Dependency; +import com.android.systemui.ForegroundServiceController; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; +import com.android.systemui.UiOffloadThread; +import com.android.systemui.appops.AppOpsController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingLog; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.car.hvac.HvacController; import com.android.systemui.statusbar.car.hvac.TemperatureView; +import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NotifPipelineInitializer; +import com.android.systemui.statusbar.notification.NotificationAlertingManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Map; +import javax.inject.Inject; +import javax.inject.Named; + /** * A status bar (and navigation bar) tailored for the automotive use case. */ @@ -175,6 +225,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private boolean mHideNavBarForKeyboard; private boolean mBottomNavBarVisible; + private final NavigationBarController mNavigationBarController; + private final CarPowerStateListener mCarPowerStateListener = (int state) -> { // When the car powers on, clear all notifications and mute/unread states. @@ -189,6 +241,116 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }; + @Inject + public CarStatusBar( + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + InjectionInflationController injectionInflationController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + NotifPipelineInitializer notifPipelineInitializer, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController) { + super( + lightBarController, + autoHideController, + keyguardUpdateMonitor, + statusBarIconController, + dozeLog, + injectionInflationController, + pulseExpansionHandler, + notificationWakeUpCoordinator, + keyguardBypassController, + keyguardStateController, + headsUpManagerPhone, + dynamicPrivacyController, + bypassHeadsUpNotifier, + allowNotificationLongPress, + notifPipelineInitializer, + falsingManager, + broadcastDispatcher, + remoteInputQuickSettingsDisabler, + notificationGutsManager, + notificationLogger, + notificationEntryManager, + notificationInterruptionStateProvider, + notificationViewHierarchyManager, + foregroundServiceController, + appOpsController, + keyguardViewMediator, + zenModeController, + notificationAlertingManager, + displayMetrics, + metricsLogger, + uiOffloadThread, + notificationMediaManager, + lockScreenUserManager, + remoteInputManager, + userSwitcherController, + networkController, + batteryController, + colorExtractor, + screenLifecycle, + wakefulnessLifecycle, + statusBarStateController, + vibratorHelper, + bubbleController, + groupManager, + groupAlertTransferHelper, + visualStabilityManager, + deviceProvisionedController, + navigationBarController, + assistManager, + notificationListener, + configurationController, + statusBarWindowController); + mNavigationBarController = navigationBarController; + } + @Override public void start() { // get the provisioned state before calling the parent class since it's that flow that diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java index ea39317fb045..81ca9eaf8e36 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java @@ -111,8 +111,9 @@ public class RecentLocationAccesses { for (int op : LOCATION_OPS) { final String permission = AppOpsManager.opToPermission(op); final int permissionFlags = pm.getPermissionFlags(permission, packageName, user); - if (PermissionChecker.checkPermission(mContext, permission, -1, uid, packageName) - == PermissionChecker.PERMISSION_GRANTED) { + if (PermissionChecker.checkPermissionForPreflight(mContext, permission, + PermissionChecker.PID_UNKNOWN, uid, packageName) + == PermissionChecker.PERMISSION_GRANTED) { if ((permissionFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) == 0) { showApp = false; diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java index 60c9984e5ed4..104cc8f9841c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java @@ -110,9 +110,9 @@ public class RecentLocationApps { final String permission = AppOpsManager.opToPermission(op); final int permissionFlags = pm.getPermissionFlags(permission, packageName, user); - if (PermissionChecker.checkPermission(mContext, permission, -1, uid, - packageName) - == PermissionChecker.PERMISSION_GRANTED) { + if (PermissionChecker.checkPermissionForPreflight(mContext, permission, + PermissionChecker.PID_UNKNOWN, uid, packageName) + == PermissionChecker.PERMISSION_GRANTED) { if ((permissionFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) == 0) { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 8c2e43170cc2..b8372adfa074 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -114,7 +114,6 @@ public class SecureSettings { Settings.Secure.ASSIST_GESTURE_WAKE_ENABLED, Settings.Secure.VR_DISPLAY_MODE, Settings.Secure.NOTIFICATION_BADGING, - Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.NOTIFICATION_DISMISS_RTL, Settings.Secure.QS_AUTO_ADDED_TILES, Settings.Secure.SCREENSAVER_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index f160edc6e446..976f3365ab98 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -157,7 +157,6 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"})); VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR); - VALIDATORS.put(Secure.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.QS_AUTO_ADDED_TILES, TILE_LIST_VALIDATOR); VALIDATORS.put(Secure.SCREENSAVER_ENABLED, BOOLEAN_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 720266a72423..16c96e67c85a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -4385,8 +4385,7 @@ public class SettingsProvider extends ContentProvider { if (currentVersion == 182) { // Remove secure bubble settings. - getSecureSettingsLocked(userId).deleteSettingLocked( - Secure.NOTIFICATION_BUBBLES); + getSecureSettingsLocked(userId).deleteSettingLocked("notification_bubbles"); // Add global bubble settings. getGlobalSettingsLocked().insertSettingLocked(Global.NOTIFICATION_BUBBLES, diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index a8ce196cc359..a3d420ee4cdf 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -104,12 +104,6 @@ it should be shown. Shows the drag handle for the divider between two apps when in split screen mode. -### [com.android.systemui.SystemBars](/packages/SystemUI/src/com/android/systemui/SystemBars.java) - -This is a proxy to the actual SystemUI for the status bar. This loads from -config_statusBarComponent which defaults to StatusBar. (maybe this should be -removed and copy how config_systemUiVendorServiceComponent works) - ### [com.android.systemui.status.phone.StatusBar](/packages/SystemUI/src/com/android/systemui/status/phone/StatusBar.java) This shows the UI for the status bar and the notification shade it contains. diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 61210d3e0011..105b27eb7e1b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -279,7 +279,7 @@ <item>com.android.systemui.recents.Recents</item> <item>com.android.systemui.volume.VolumeUI</item> <item>com.android.systemui.stackdivider.Divider</item> - <item>com.android.systemui.SystemBars</item> + <item>com.android.systemui.statusbar.phone.StatusBar</item> <item>com.android.systemui.usb.StorageNotification</item> <item>com.android.systemui.power.PowerUI</item> <item>com.android.systemui.media.RingtonePlayer</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 8d167e8783bf..b9fe9334d14c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -76,7 +76,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe // How much you need to drag the bouncer to trigger an auth retry (in dps.) private static final float MIN_DRAG_SIZE = 10; // How much to scale the default slop by, to avoid accidental drags. - private static final float SLOP_SCALE = 2f; + private static final float SLOP_SCALE = 4f; private KeyguardSecurityModel mSecurityModel; private LockPatternUtils mLockPatternUtils; @@ -128,7 +128,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mSecurityModel = new KeyguardSecurityModel(context); + mSecurityModel = Dependency.get(KeyguardSecurityModel.class); mLockPatternUtils = new LockPatternUtils(context); mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index bb89959b7a11..1395fd9e3482 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -25,6 +25,10 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton public class KeyguardSecurityModel { /** @@ -46,6 +50,7 @@ public class KeyguardSecurityModel { private LockPatternUtils mLockPatternUtils; + @Inject KeyguardSecurityModel(Context context) { mContext = context; mLockPatternUtils = new LockPatternUtils(context); @@ -57,7 +62,7 @@ public class KeyguardSecurityModel { mLockPatternUtils = utils; } - SecurityMode getSecurityMode(int userId) { + public SecurityMode getSecurityMode(int userId) { KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a6b3be23417e..dc8ee16e8645 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -58,6 +58,7 @@ import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.database.ContentObserver; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; @@ -329,6 +330,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray(); private SparseBooleanArray mUserHasTrust = new SparseBooleanArray(); private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray(); + private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray(); private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray(); private SparseBooleanArray mUserFaceAuthenticated = new SparseBooleanArray(); private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray(); @@ -472,6 +474,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { public void onTrustManagedChanged(boolean managed, int userId) { checkIsHandlerThread(); mUserTrustIsManaged.put(userId, managed); + mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -925,6 +928,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId); } + /** + * Cached version of {@link TrustManager#isTrustUsuallyManaged(int)}. + */ + public boolean isTrustUsuallyManaged(int userId) { + checkIsHandlerThread(); + return mUserTrustIsUsuallyManaged.get(userId); + } + public boolean isUnlockingWithBiometricAllowed() { return mStrongAuthTracker.isUnlockingWithBiometricAllowed(); } @@ -1474,9 +1485,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mUserIsUnlocked.put(userId, mUserManager.isUserUnlocked(userId)); } - private void handleUserRemoved(int userId) { + @VisibleForTesting + void handleUserRemoved(int userId) { checkIsHandlerThread(); mUserIsUnlocked.delete(userId); + mUserTrustIsUsuallyManaged.delete(userId); } @VisibleForTesting @@ -1662,7 +1675,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { e.rethrowAsRuntimeException(); } - mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); + mTrustManager = context.getSystemService(TrustManager.class); mTrustManager.registerTrustListener(this); mLockPatternUtils = new LockPatternUtils(context); mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); @@ -1697,6 +1710,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user)); mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled(); + List<UserInfo> allUsers = mUserManager.getUsers(); + for (UserInfo userInfo : allUsers) { + mUserTrustIsUsuallyManaged.put(userInfo.id, + mTrustManager.isTrustUsuallyManaged(userInfo.id)); + } updateAirplaneModeState(); TelephonyManager telephony = @@ -2048,6 +2066,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { */ private void handleUserSwitching(int userId, IRemoteCallback reply) { checkIsHandlerThread(); + mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 37bb54cc1b11..07bfa7194413 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -30,6 +30,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.Preconditions; +import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.clock.ClockManager; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -316,6 +317,7 @@ public class Dependency { @Inject Lazy<FalsingManager> mFalsingManager; @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; @Inject Lazy<AlarmManager> mAlarmManager; + @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel; @Inject public Dependency() { @@ -501,6 +503,7 @@ public class Dependency { mProviders.put(FalsingManager.class, mFalsingManager::get); mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); mProviders.put(AlarmManager.class, mAlarmManager::get); + mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java index c4dce1e70051..f9f0f1bad2fa 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java @@ -200,6 +200,12 @@ public abstract class DependencyBinder { /** */ @Binds + public abstract SysuiStatusBarStateController providesSysuiStatusBarStateController( + StatusBarStateControllerImpl statusBarStateControllerImpl); + + /** + */ + @Binds public abstract StatusBarIconController provideStatusBarIconController( StatusBarIconControllerImpl controllerImpl); @@ -235,10 +241,4 @@ public abstract class DependencyBinder { */ @Binds public abstract FalsingManager provideFalsingmanager(FalsingManagerProxy falsingManagerImpl); - - /** - */ - @Binds - public abstract SysuiStatusBarStateController providesSysuiStatusBarStateController( - StatusBarStateControllerImpl statusBarStateControllerImpl); } diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java index 239cbfe38975..0d24321d8db7 100644 --- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java @@ -40,6 +40,7 @@ import android.view.WindowManagerGlobal; import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.plugins.PluginInitializerImpl; import com.android.systemui.shared.plugins.PluginManager; @@ -238,4 +239,10 @@ public class DependencyProvider { public AlarmManager provideAlarmManager(Context context) { return context.getSystemService(AlarmManager.class); } + + /** */ + @Provides + public LockPatternUtils provideLockPatternUtils(Context context) { + return new LockPatternUtils(context); + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemBars.java b/packages/SystemUI/src/com/android/systemui/SystemBars.java deleted file mode 100644 index c4c0fd6da124..000000000000 --- a/packages/SystemUI/src/com/android/systemui/SystemBars.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui; - -import android.util.Log; - -import com.android.systemui.statusbar.phone.StatusBar; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Ensure a single status bar service implementation is running at all times, using the in-process - * implementation according to the product config. - */ -public class SystemBars extends SystemUI { - private static final String TAG = "SystemBars"; - private static final boolean DEBUG = false; - private static final int WAIT_FOR_BARS_TO_DIE = 500; - - // in-process fallback implementation, per the product config - private SystemUI mStatusBar; - - @Override - public void start() { - if (DEBUG) Log.d(TAG, "start"); - createStatusBarFromConfig(); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mStatusBar != null) { - mStatusBar.dump(fd, pw, args); - } - } - - @Override - public void onBootCompleted() { - if (mStatusBar != null) { - mStatusBar.onBootCompleted(); - } - } - - private void createStatusBarFromConfig() { - if (DEBUG) Log.d(TAG, "createStatusBarFromConfig"); - final String clsName = mContext.getString(R.string.config_statusBarComponent); - if (clsName == null || clsName.length() == 0) { - throw andLog("No status bar component configured", null); - } - Class<?> cls = null; - try { - cls = mContext.getClassLoader().loadClass(clsName); - } catch (Throwable t) { - throw andLog("Error loading status bar component: " + clsName, t); - } - try { - mStatusBar = (SystemUI) cls.newInstance(); - } catch (Throwable t) { - throw andLog("Error creating status bar component: " + clsName, t); - } - mStatusBar.mContext = mContext; - mStatusBar.mComponents = mComponents; - if (mStatusBar instanceof StatusBar) { - SystemUIFactory.getInstance().getRootComponent() - .getStatusBarInjector() - .createStatusBar((StatusBar) mStatusBar); - } - mStatusBar.start(); - if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName()); - } - - private RuntimeException andLog(String msg, Throwable t) { - Log.w(TAG, msg, t); - throw new RuntimeException(msg, t); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java index ba2dec0ff116..785038f2b7f7 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java @@ -44,7 +44,7 @@ public abstract class SystemUIBinder { @ClassKey(PowerUI.class) public abstract SystemUI bindPowerUI(PowerUI sysui); - /** Inject into StatusBar. */ + /** Inject into Recents. */ @Binds @IntoMap @ClassKey(Recents.class) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java index 262b5ec50d83..72831e99e122 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java @@ -40,6 +40,8 @@ import javax.inject.Singleton; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; /** * A dagger module for injecting default implementations of components of System UI that may be @@ -76,6 +78,11 @@ abstract class SystemUIDefaultModule { return SysUiServiceProvider.getComponent(context, StatusBar.class); } + @Binds + @IntoMap + @ClassKey(StatusBar.class) + public abstract SystemUI providesStatusBar(StatusBar statusBar); + @Singleton @Provides @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java index cb7c998fad8e..8105c6a6e940 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java @@ -37,7 +37,7 @@ import java.util.Locale; * adb shell setprop debug.falsing_log true * * The log gets dumped as part of the SystemUI services. To dump on demand: - * adb shell dumpsys activity service com.android.systemui SystemBars | grep -A 999 FALSING | less + * adb shell dumpsys activity service com.android.systemui StatusBar | grep -A 999 FALSING | less * * To dump into logcat: * adb shell setprop debug.falsing_logcat true diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index f159d8c1d431..a8027c025cf2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -234,7 +234,7 @@ public class KeyguardViewMediator extends SystemUI { */ private PowerManager.WakeLock mShowKeyguardWakeLock; - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; // these are protected by synchronized (this) @@ -317,7 +317,7 @@ public class KeyguardViewMediator extends SystemUI { * the keyguard. */ private boolean mWaitingUntilKeyguardVisible = false; - private LockPatternUtils mLockPatternUtils; + private final LockPatternUtils mLockPatternUtils; private boolean mKeyguardDonePending = false; private boolean mHideAnimationRun = false; private boolean mHideAnimationRunning = false; @@ -650,29 +650,26 @@ public class KeyguardViewMediator extends SystemUI { @Override public int getBouncerPromptReason() { - // TODO(b/140053364) - return whitelistIpcs(() -> { - int currentUser = ActivityManager.getCurrentUser(); - boolean trust = mTrustManager.isTrustUsuallyManaged(currentUser); - boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser); - boolean any = trust || biometrics; - KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker = - mUpdateMonitor.getStrongAuthTracker(); - int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser); - - if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) { - return KeyguardSecurityView.PROMPT_REASON_RESTART; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) { - return KeyguardSecurityView.PROMPT_REASON_TIMEOUT; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) { - return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; - } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { - return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; - } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) { - return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; - } - return KeyguardSecurityView.PROMPT_REASON_NONE; - }); + int currentUser = KeyguardUpdateMonitor.getCurrentUser(); + boolean trust = mUpdateMonitor.isTrustUsuallyManaged(currentUser); + boolean biometrics = mUpdateMonitor.isUnlockingWithBiometricsPossible(currentUser); + boolean any = trust || biometrics; + KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker = + mUpdateMonitor.getStrongAuthTracker(); + int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser); + + if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) { + return KeyguardSecurityView.PROMPT_REASON_RESTART; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) { + return KeyguardSecurityView.PROMPT_REASON_TIMEOUT; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) { + return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN; + } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { + return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; + } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) { + return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; + } + return KeyguardSecurityView.PROMPT_REASON_NONE; } @Override @@ -684,10 +681,21 @@ public class KeyguardViewMediator extends SystemUI { }; @Inject - public KeyguardViewMediator(FalsingManager falsingManager) { + public KeyguardViewMediator( + Context context, + FalsingManager falsingManager, + LockPatternUtils lockPatternUtils) { super(); + mContext = context; mFalsingManager = falsingManager; + + mLockPatternUtils = lockPatternUtils; + mStatusBarKeyguardViewManager = + SystemUIFactory.getInstance().createStatusBarKeyguardViewManager( + mContext, + mViewMediatorCallback, + mLockPatternUtils); } public void userActivity() { @@ -701,7 +709,7 @@ public class KeyguardViewMediator extends SystemUI { private void setupLocked() { mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE); + mTrustManager = mContext.getSystemService(TrustManager.class); mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); mShowKeyguardWakeLock.setReferenceCounted(false); @@ -725,7 +733,6 @@ public class KeyguardViewMediator extends SystemUI { mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); - mLockPatternUtils = new LockPatternUtils(mContext); KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); // Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard @@ -739,9 +746,6 @@ public class KeyguardViewMediator extends SystemUI { setShowingLocked(false /* showing */, true /* forceCallbacks */); } - mStatusBarKeyguardViewManager = - SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext, - mViewMediatorCallback, mLockPatternUtils); final ContentResolver cr = mContext.getContentResolver(); mDeviceInteractive = mPM.isInteractive(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 90301c59dc68..148a1a87f305 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -20,7 +20,6 @@ import static android.service.notification.NotificationListenerService.REASON_ER import android.annotation.Nullable; import android.app.Notification; -import android.content.Context; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; @@ -124,8 +123,8 @@ public class NotificationEntryManager implements } @Inject - public NotificationEntryManager(Context context) { - mNotificationData = new NotificationData(context); + public NotificationEntryManager(NotificationData notificationData) { + mNotificationData = notificationData; } /** Adds a {@link NotificationEntryListener}. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt new file mode 100644 index 000000000000..480cb78efbba --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification + +import android.content.Context +import android.provider.DeviceConfig + +import com.android.internal.annotations.VisibleForTesting +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT +import com.android.systemui.util.DeviceConfigProxy + +import javax.inject.Inject + +private var sUsePeopleFiltering: Boolean? = null + +/** + * Feature controller for the NOTIFICATIONS_USE_PEOPLE_FILTERING config. + */ +class NotificationSectionsFeatureManager @Inject constructor( + val proxy: DeviceConfigProxy, + val context: Context +) { + + fun isFilteringEnabled(): Boolean { + return usePeopleFiltering(proxy) + } + + fun getNotificationBuckets(): IntArray { + return when { + isFilteringEnabled() -> + intArrayOf(BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) + NotificationUtils.useNewInterruptionModel(context) -> + intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) + else -> + intArrayOf(BUCKET_ALERTING) + } + } + + fun getNumberOfBuckets(): Int { + return getNotificationBuckets().size + } + + @VisibleForTesting + fun clearCache() { + sUsePeopleFiltering = null + } +} + +private fun usePeopleFiltering(proxy: DeviceConfigProxy): Boolean { + if (sUsePeopleFiltering == null) { + sUsePeopleFiltering = proxy.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, false) + } + + return sUsePeopleFiltering!! +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java index dfbbf987dd96..1af47dd0f4c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java @@ -36,7 +36,6 @@ public class NotificationUtils { private static final int[] sLocationOffset = new int[2]; @Nullable private static Boolean sUseNewInterruptionModel = null; - @Nullable private static Boolean sUsePeopleFiltering = null; public static boolean isGrayscale(ImageView v, ContrastColorUtil colorUtil) { Object isGrayscale = v.getTag(R.id.icon_is_grayscale); @@ -88,17 +87,4 @@ public class NotificationUtils { } return sUseNewInterruptionModel; } - - /** - * Caches and returns the value of the people filtering setting. Cannot change except through - * process restarts. - */ - public static boolean usePeopleFiltering(Context context) { - if (sUsePeopleFiltering == null) { - sUsePeopleFiltering = context.getResources().getBoolean( - R.bool.config_usePeopleFiltering); - } - - return sUsePeopleFiltering; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java index aacb2dd0682f..cf0fbbb5d9c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java @@ -24,7 +24,6 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Person; -import android.content.Context; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; @@ -35,7 +34,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -46,6 +45,8 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; +import javax.inject.Inject; + /** * The list of currently displaying notifications. */ @@ -73,8 +74,9 @@ public class NotificationData { private final Ranking mTmpRanking = new Ranking(); private final boolean mUsePeopleFiltering; - public NotificationData(Context context) { - mUsePeopleFiltering = NotificationUtils.usePeopleFiltering(context); + @Inject + public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) { + mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled(); } public void setHeadsUpManager(HeadsUpManager headsUpManager) { @@ -483,19 +485,6 @@ public class NotificationData { } /** - * Get the current set of buckets for notification entries, as defined here - */ - public static int[] getNotificationBuckets(Context context) { - if (NotificationUtils.usePeopleFiltering(context)) { - return new int[]{BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT}; - } else if (NotificationUtils.useNewInterruptionModel(context)) { - return new int[]{BUCKET_ALERTING, BUCKET_SILENT}; - } else { - return new int[]{BUCKET_ALERTING}; - } - } - - /** * Provides access to keyguard state and user settings dependent data. */ public interface KeyguardEnvironment { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index ec0c6348fd89..b4f7b59349d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -16,10 +16,9 @@ package com.android.systemui.statusbar.notification.stack; -import android.content.Context; import android.util.MathUtils; -import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -52,8 +51,8 @@ public class NotificationRoundnessManager implements OnHeadsUpChangedListener { @Inject NotificationRoundnessManager( KeyguardBypassController keyguardBypassController, - Context context) { - int numberOfSections = NotificationData.getNotificationBuckets(context).length; + NotificationSectionsFeatureManager sectionsFeatureManager) { + int numberOfSections = sectionsFeatureManager.getNumberOfBuckets(); mFirstInSectionViews = new ActivatableNotificationView[numberOfSections]; mLastInSectionViews = new ActivatableNotificationView[numberOfSections]; mTmpFirstInSectionViews = new ActivatableNotificationView[numberOfSections]; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index a67018ef9710..f5705c5f643b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -109,11 +109,11 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.ShadeViewRefactor; import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -517,7 +517,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd StatusBarStateController statusBarStateController, HeadsUpManagerPhone headsUpManager, KeyguardBypassController keyguardBypassController, - FalsingManager falsingManager) { + FalsingManager falsingManager, + NotificationSectionsFeatureManager sectionsFeatureManager) { super(context, attrs, 0, 0); Resources res = getResources(); @@ -531,7 +532,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mKeyguardBypassController = keyguardBypassController; mFalsingManager = falsingManager; - int[] buckets = NotificationData.getNotificationBuckets(context); + int[] buckets = sectionsFeatureManager.getNotificationBuckets(); mSectionsManager = new NotificationSectionsManager( this, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 68eca8d68d90..cac33044ea13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -117,6 +117,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private static final int DOZE_ANIMATION_STAGGER_DELAY = 48; private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250; + private final boolean mShowLeftAffordance; + private final boolean mShowCameraAffordance; + private KeyguardAffordanceView mRightAffordanceView; private KeyguardAffordanceView mLeftAffordanceView; private ViewGroup mIndicationArea; @@ -184,6 +187,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + mShowLeftAffordance = getResources().getBoolean(R.bool.config_keyguardShowLeftAffordance); + mShowCameraAffordance = getResources() + .getBoolean(R.bool.config_keyguardShowCameraAffordance); } private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() { @@ -371,8 +377,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL // Things are not set up yet; reply hazy, ask again later return; } - mRightAffordanceView.setVisibility(!mDozing && mRightButton.getIcon().isVisible - ? View.VISIBLE : View.GONE); + mRightAffordanceView.setVisibility(!mDozing && mShowCameraAffordance + && mRightButton.getIcon().isVisible ? View.VISIBLE : View.GONE); } /** @@ -384,8 +390,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } private void updateLeftAffordanceIcon() { + if (!mShowLeftAffordance || mDozing) { + mLeftAffordanceView.setVisibility(GONE); + return; + } IconState state = mLeftButton.getIcon(); - mLeftAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE); + mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE); if (state.drawable != mLeftAffordanceView.getDrawable() || state.tint != mLeftAffordanceView.shouldTint()) { mLeftAffordanceView.setImageDrawable(state.drawable, state.tint); @@ -767,10 +777,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public IconState getIcon() { mLeftIsVoiceAssist = canLaunchVoiceAssist(); - final boolean showAffordance = - getResources().getBoolean(R.bool.config_keyguardShowLeftAffordance); if (mLeftIsVoiceAssist) { - mIconState.isVisible = mUserSetupComplete && showAffordance; + mIconState.isVisible = mUserSetupComplete && mShowLeftAffordance; if (mLeftAssistIcon == null) { mIconState.drawable = mContext.getDrawable(R.drawable.ic_mic_26dp); } else { @@ -779,7 +787,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mIconState.contentDescription = mContext.getString( R.string.accessibility_voice_assist_button); } else { - mIconState.isVisible = mUserSetupComplete && showAffordance && isPhoneVisible(); + mIconState.isVisible = mUserSetupComplete && mShowLeftAffordance + && isPhoneVisible(); mIconState.drawable = mContext.getDrawable( com.android.internal.R.drawable.ic_phone); mIconState.contentDescription = mContext.getString( @@ -802,7 +811,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public IconState getIcon() { boolean isCameraDisabled = (mStatusBar != null) && !mStatusBar.isCameraAllowedByAdmin(); mIconState.isVisible = !isCameraDisabled - && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance) + && mShowCameraAffordance && mUserSetupComplete && resolveCameraIntent() != null; mIconState.drawable = mContext.getDrawable(R.drawable.ic_camera_alt_24dp); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index c3de84366d4b..f34c15c7099d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone; import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; -import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; import android.content.Context; @@ -38,11 +37,13 @@ import android.view.WindowInsets; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardHostView; +import com.android.keyguard.KeyguardSecurityModel; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; @@ -461,15 +462,9 @@ public class KeyguardBouncer { * notifications on Keyguard, like SIM PIN/PUK. */ public boolean needsFullscreenBouncer() { - // TODO(b/140059518) - return whitelistIpcs(() -> { - ensureView(); - if (mKeyguardView != null) { - SecurityMode mode = mKeyguardView.getSecurityMode(); - return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; - } - return false; - }); + SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode( + KeyguardUpdateMonitor.getCurrentUser()); + return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index e79f14175377..b1825c8ce667 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -25,7 +25,6 @@ import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; -import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import static com.android.systemui.Dependency.BG_HANDLER; import static com.android.systemui.Dependency.MAIN_HANDLER; @@ -347,10 +346,9 @@ public class StatusBar extends SystemUI implements DemoMode, private BrightnessMirrorController mBrightnessMirrorController; private boolean mBrightnessMirrorVisible; protected BiometricUnlockController mBiometricUnlockController; - @Inject LightBarController mLightBarController; + private final LightBarController mLightBarController; protected LockscreenWallpaper mLockscreenWallpaper; - @VisibleForTesting - @Inject AutoHideController mAutoHideController; + private final AutoHideController mAutoHideController; private int mNaturalBarHeight = -1; @@ -360,8 +358,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected PhoneStatusBarView mStatusBarView; private int mStatusBarWindowState = WINDOW_STATE_SHOWING; protected StatusBarWindowController mStatusBarWindowController; - @VisibleForTesting - @Inject KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @VisibleForTesting DozeServiceHost mDozeServiceHost = new DozeServiceHost(); private boolean mWakeUpComingFromTouch; @@ -369,38 +366,21 @@ public class StatusBar extends SystemUI implements DemoMode, private final Object mQueueLock = new Object(); - @Inject StatusBarIconController mIconController; - @Inject - DozeLog mDozeLog; - @Inject - InjectionInflationController mInjectionInflater; - @Inject - PulseExpansionHandler mPulseExpansionHandler; - @Inject - NotificationWakeUpCoordinator mWakeUpCoordinator; - @Inject - KeyguardBypassController mKeyguardBypassController; - @Inject - KeyguardStateController mKeyguardStateController; - @Inject - protected HeadsUpManagerPhone mHeadsUpManager; - @Inject - DynamicPrivacyController mDynamicPrivacyController; - @Inject - BypassHeadsUpNotifier mBypassHeadsUpNotifier; - @Nullable - @Inject - protected KeyguardLiftController mKeyguardLiftController; - @Inject - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) - boolean mAllowNotificationLongPress; - @Inject - protected NotifPipelineInitializer mNotifPipelineInitializer; - @Inject - protected FalsingManager mFalsingManager; - - @VisibleForTesting - @Inject BroadcastDispatcher mBroadcastDispatcher; + private final StatusBarIconController mIconController; + private final DozeLog mDozeLog; + private final InjectionInflationController mInjectionInflater; + private final PulseExpansionHandler mPulseExpansionHandler; + private final NotificationWakeUpCoordinator mWakeUpCoordinator; + private final KeyguardBypassController mKeyguardBypassController; + private final KeyguardStateController mKeyguardStateController; + private final HeadsUpManagerPhone mHeadsUpManager; + private final DynamicPrivacyController mDynamicPrivacyController; + private final BypassHeadsUpNotifier mBypassHeadsUpNotifier; + private final boolean mAllowNotificationLongPress; + private final NotifPipelineInitializer mNotifPipelineInitializer; + private final FalsingManager mFalsingManager; + private final BroadcastDispatcher mBroadcastDispatcher; + private final ConfigurationController mConfigurationController; // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -413,7 +393,7 @@ public class StatusBar extends SystemUI implements DemoMode, // RemoteInputView to be activated after unlock private View mPendingRemoteInputView; - @Inject RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; + private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private View mReportRejectedTouch; @@ -422,17 +402,17 @@ public class StatusBar extends SystemUI implements DemoMode, private final int[] mAbsPos = new int[2]; private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); - @Inject NotificationGutsManager mGutsManager; - @Inject NotificationLogger mNotificationLogger; - @Inject NotificationEntryManager mEntryManager; + private final NotificationGutsManager mGutsManager; + private final NotificationLogger mNotificationLogger; + private final NotificationEntryManager mEntryManager; private NotificationListController mNotificationListController; - @Inject NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - @Inject NotificationViewHierarchyManager mViewHierarchyManager; - @Inject ForegroundServiceController mForegroundServiceController; - @Inject AppOpsController mAppOpsController; - @Inject KeyguardViewMediator mKeyguardViewMediator; - @Inject ZenModeController mZenController; - @Inject NotificationAlertingManager mNotificationAlertingManager; + private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationViewHierarchyManager mViewHierarchyManager; + private final ForegroundServiceController mForegroundServiceController; + private final AppOpsController mAppOpsController; + private final KeyguardViewMediator mKeyguardViewMediator; + private final ZenModeController mZenController; + private final NotificationAlertingManager mNotificationAlertingManager; // for disabling the status bar private int mDisabled1 = 0; @@ -443,7 +423,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Rect mLastFullscreenStackBounds = new Rect(); private final Rect mLastDockedStackBounds = new Rect(); - @Inject DisplayMetrics mDisplayMetrics; + private final DisplayMetrics mDisplayMetrics; // XXX: gesture research private final GestureRecorder mGestureRec = DEBUG_GESTURES @@ -452,7 +432,7 @@ public class StatusBar extends SystemUI implements DemoMode, private ScreenPinningRequest mScreenPinningRequest; - @Inject MetricsLogger mMetricsLogger; + private final MetricsLogger mMetricsLogger; // ensure quick settings is disabled until the current user makes it through the setup wizard @VisibleForTesting @@ -489,14 +469,14 @@ public class StatusBar extends SystemUI implements DemoMode, private ViewMediatorCallback mKeyguardViewMediatorCallback; protected ScrimController mScrimController; protected DozeScrimController mDozeScrimController; - @Inject UiOffloadThread mUiOffloadThread; + private final UiOffloadThread mUiOffloadThread; protected boolean mDozing; private boolean mDozingRequested; - @Inject NotificationMediaManager mMediaManager; - @Inject NotificationLockscreenUserManager mLockscreenUserManager; - @Inject NotificationRemoteInputManager mRemoteInputManager; + private final NotificationMediaManager mMediaManager; + private final NotificationLockscreenUserManager mLockscreenUserManager; + private final NotificationRemoteInputManager mRemoteInputManager; private boolean mWallpaperSupported; private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() { @@ -567,18 +547,18 @@ public class StatusBar extends SystemUI implements DemoMode, }; private KeyguardUserSwitcher mKeyguardUserSwitcher; - @Inject UserSwitcherController mUserSwitcherController; - @Inject NetworkController mNetworkController; - @Inject BatteryController mBatteryController; + private final UserSwitcherController mUserSwitcherController; + private final NetworkController mNetworkController; + private final BatteryController mBatteryController; protected boolean mPanelExpanded; private UiModeManager mUiModeManager; protected boolean mIsKeyguard; private LogMaker mStatusBarStateLog; protected NotificationIconAreaController mNotificationIconAreaController; @Nullable private View mAmbientIndicationContainer; - @Inject SysuiColorExtractor mColorExtractor; - @Inject ScreenLifecycle mScreenLifecycle; - @Inject @VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle; + private final SysuiColorExtractor mColorExtractor; + private final ScreenLifecycle mScreenLifecycle; + private final WakefulnessLifecycle mWakefulnessLifecycle; private final View.OnClickListener mGoToLockedShadeListener = v -> { if (mState == StatusBarState.KEYGUARD) { @@ -587,7 +567,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }; private boolean mNoAnimationOnNextBarModeChange; - @Inject SysuiStatusBarStateController mStatusBarStateController; + private final SysuiStatusBarStateController mStatusBarStateController; private final KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -608,17 +588,13 @@ public class StatusBar extends SystemUI implements DemoMode, private HeadsUpAppearanceController mHeadsUpAppearanceController; private boolean mVibrateOnOpening; - @Inject VibratorHelper mVibratorHelper; + private final VibratorHelper mVibratorHelper; private ActivityLaunchAnimator mActivityLaunchAnimator; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private boolean mPulsing; - @Inject BubbleController mBubbleController; - private final BubbleController.BubbleExpandListener mBubbleExpandListener = - (isExpanding, key) -> { - mEntryManager.updateNotifications(); - updateScrimController(); - }; + private final BubbleController mBubbleController; + private final BubbleController.BubbleExpandListener mBubbleExpandListener; private ActivityIntentHelper mActivityIntentHelper; @Override @@ -635,6 +611,120 @@ public class StatusBar extends SystemUI implements DemoMode, AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_FINE_LOCATION}; + @Inject + public StatusBar( + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + DozeLog dozeLog, + InjectionInflationController injectionInflationController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress, + NotifPipelineInitializer notifPipelineInitializer, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationEntryManager notificationEntryManager, + NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + ForegroundServiceController foregroundServiceController, + AppOpsController appOpsController, + KeyguardViewMediator keyguardViewMediator, + ZenModeController zenModeController, + NotificationAlertingManager notificationAlertingManager, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + UiOffloadThread uiOffloadThread, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + NotificationGroupAlertTransferHelper groupAlertTransferHelper, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + AssistManager assistManager, + NotificationListener notificationListener, + ConfigurationController configurationController, + StatusBarWindowController statusBarWindowController) { + mLightBarController = lightBarController; + mAutoHideController = autoHideController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mIconController = statusBarIconController; + mDozeLog = dozeLog; + mInjectionInflater = injectionInflationController; + mPulseExpansionHandler = pulseExpansionHandler; + mWakeUpCoordinator = notificationWakeUpCoordinator; + mKeyguardBypassController = keyguardBypassController; + mKeyguardStateController = keyguardStateController; + mHeadsUpManager = headsUpManagerPhone; + mDynamicPrivacyController = dynamicPrivacyController; + mBypassHeadsUpNotifier = bypassHeadsUpNotifier; + mAllowNotificationLongPress = allowNotificationLongPress; + mNotifPipelineInitializer = notifPipelineInitializer; + mFalsingManager = falsingManager; + mBroadcastDispatcher = broadcastDispatcher; + mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; + mGutsManager = notificationGutsManager; + mNotificationLogger = notificationLogger; + mEntryManager = notificationEntryManager; + mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mViewHierarchyManager = notificationViewHierarchyManager; + mForegroundServiceController = foregroundServiceController; + mAppOpsController = appOpsController; + mKeyguardViewMediator = keyguardViewMediator; + mZenController = zenModeController; + mNotificationAlertingManager = notificationAlertingManager; + mDisplayMetrics = displayMetrics; + mMetricsLogger = metricsLogger; + mUiOffloadThread = uiOffloadThread; + mMediaManager = notificationMediaManager; + mLockscreenUserManager = lockScreenUserManager; + mRemoteInputManager = remoteInputManager; + mUserSwitcherController = userSwitcherController; + mNetworkController = networkController; + mBatteryController = batteryController; + mColorExtractor = colorExtractor; + mScreenLifecycle = screenLifecycle; + mWakefulnessLifecycle = wakefulnessLifecycle; + mStatusBarStateController = statusBarStateController; + mVibratorHelper = vibratorHelper; + mBubbleController = bubbleController; + mGroupManager = groupManager; + mGroupAlertTransferHelper = groupAlertTransferHelper; + mVisualStabilityManager = visualStabilityManager; + mDeviceProvisionedController = deviceProvisionedController; + mNavigationBarController = navigationBarController; + mAssistManager = assistManager; + mNotificationListener = notificationListener; + mConfigurationController = configurationController; + mStatusBarWindowController = statusBarWindowController; + + mBubbleExpandListener = + (isExpanding, key) -> { + mEntryManager.updateNotifications(); + updateScrimController(); + }; + } + @Override public void start() { mNotificationListener.registerAsSystemService(); @@ -772,7 +862,7 @@ public class StatusBar extends SystemUI implements DemoMode, Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); - Dependency.get(ConfigurationController.class).addCallback(this); + mConfigurationController.addCallback(this); // set the initial view visibility Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications); @@ -805,6 +895,8 @@ public class StatusBar extends SystemUI implements DemoMode, NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller; mNotificationLogger.setUpWithContainer(notifListContainer); + // TODO: make this injectable. Currently that would create a circular dependency between + // NotificationIconAreaController and StatusBar. mNotificationIconAreaController = SystemUIFactory.getInstance() .createNotificationIconAreaController(context, this, mWakeUpCoordinator, mKeyguardBypassController, @@ -869,7 +961,7 @@ public class StatusBar extends SystemUI implements DemoMode, .commit(); mHeadsUpManager.setUp(mStatusBarWindow, mGroupManager, this, mVisualStabilityManager); - Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager); + mConfigurationController.addCallback(mHeadsUpManager); mHeadsUpManager.addListener(this); mHeadsUpManager.addListener(mNotificationPanel); mHeadsUpManager.addListener(mGroupManager); @@ -1004,11 +1096,10 @@ public class StatusBar extends SystemUI implements DemoMode, }); } - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - if (!pm.isScreenOn()) { + if (!mPowerManager.isScreenOn()) { mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF)); } - mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, + mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GestureWakeLock"); mVibrator = mContext.getSystemService(Vibrator.class); int[] pattern = mContext.getResources().getIntArray( @@ -1131,8 +1222,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void wakeUpIfDozing(long time, View where, String why) { if (mDozing) { - PowerManager pm = mContext.getSystemService(PowerManager.class); - pm.wakeUp(time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); + mPowerManager.wakeUp( + time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why); mWakeUpComingFromTouch = true; where.getLocationInWindow(mTmpInt2); mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2, @@ -1232,13 +1323,12 @@ public class StatusBar extends SystemUI implements DemoMode, protected void startKeyguard() { Trace.beginSection("StatusBar#startKeyguard"); - KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class); mBiometricUnlockController = new BiometricUnlockController(mContext, - mDozeScrimController, keyguardViewMediator, + mDozeScrimController, mKeyguardViewMediator, mScrimController, this, mKeyguardStateController, new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController); putComponent(BiometricUnlockController.class, mBiometricUnlockController); - mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this, + mStatusBarKeyguardViewManager = mKeyguardViewMediator.registerStatusBar(this, getBouncerContainer(), mNotificationPanel, mBiometricUnlockController, mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller, mKeyguardBypassController); @@ -1248,7 +1338,7 @@ public class StatusBar extends SystemUI implements DemoMode, mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); - mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); + mKeyguardViewMediatorCallback = mKeyguardViewMediator.getViewMediatorCallback(); mLightBarController.setBiometricUnlockController(mBiometricUnlockController); mMediaManager.setBiometricUnlockController(mBiometricUnlockController); Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked); @@ -1734,6 +1824,16 @@ public class StatusBar extends SystemUI implements DemoMode, return mPresenter; } + @VisibleForTesting + void setBarStateForTest(int state) { + mState = state; + } + + @VisibleForTesting + void setUserSetupForTest(boolean userSetup) { + mUserSetup = userSetup; + } + /** * All changes to the status bar and notifications funnel through here and are batched. */ @@ -2425,7 +2525,6 @@ public class StatusBar extends SystemUI implements DemoMode, public void createAndAddWindows(@Nullable RegisterStatusBarResult result) { makeStatusBarView(result); - mStatusBarWindowController = Dependency.get(StatusBarWindowController.class); mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight()); } @@ -2669,7 +2768,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - // SystemUIService notifies SystemBars of configuration changes, which then calls down here @Override public void onConfigChanged(Configuration newConfig) { updateResources(); @@ -3251,7 +3349,7 @@ public class StatusBar extends SystemUI implements DemoMode, final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; if (mContext.getThemeResId() != themeResId) { mContext.setTheme(themeResId); - Dependency.get(ConfigurationController.class).notifyThemeChanged(); + mConfigurationController.notifyThemeChanged(); } } @@ -3798,8 +3896,7 @@ public class StatusBar extends SystemUI implements DemoMode, return; } if (!mDeviceInteractive) { - PowerManager pm = mContext.getSystemService(PowerManager.class); - pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, + mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, "com.android.systemui:CAMERA_GESTURE"); } vibrateForCameraGesture(); @@ -3838,20 +3935,17 @@ public class StatusBar extends SystemUI implements DemoMode, } boolean isCameraAllowedByAdmin() { - // TODO(b/140060745) - return whitelistIpcs(() -> { - if (mDevicePolicyManager.getCameraDisabled(null, - mLockscreenUserManager.getCurrentUserId())) { - return false; - } else if (mStatusBarKeyguardViewManager == null - || (isKeyguardShowing() && isKeyguardSecure())) { - // Check if the admin has disabled the camera specifically for the keyguard - return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, - mLockscreenUserManager.getCurrentUserId()) - & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0; - } - return true; - }); + if (mDevicePolicyManager.getCameraDisabled(null, + mLockscreenUserManager.getCurrentUserId())) { + return false; + } else if (mStatusBarKeyguardViewManager == null + || (isKeyguardShowing() && isKeyguardSecure())) { + // Check if the admin has disabled the camera specifically for the keyguard + return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, + mLockscreenUserManager.getCurrentUserId()) + & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0; + } + return true; } private boolean isGoingToSleep() { @@ -4188,11 +4282,11 @@ public class StatusBar extends SystemUI implements DemoMode, // all notifications protected ViewGroup mStackScroller; - @Inject NotificationGroupManager mGroupManager; - @Inject NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; + private final NotificationGroupManager mGroupManager; + private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; // handling reordering - @Inject VisualStabilityManager mVisualStabilityManager; + private final VisualStabilityManager mVisualStabilityManager; protected AccessibilityManager mAccessibilityManager; @@ -4208,9 +4302,9 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected KeyguardManager mKeyguardManager; - @Inject DeviceProvisionedController mDeviceProvisionedController; + private final DeviceProvisionedController mDeviceProvisionedController; - @Inject protected NavigationBarController mNavigationBarController; + private final NavigationBarController mNavigationBarController; // UI-specific methods @@ -4226,7 +4320,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationShelf mNotificationShelf; protected EmptyShadeView mEmptyShadeView; - @Inject AssistManager mAssistManager; + private final AssistManager mAssistManager; public boolean isDeviceInteractive() { return mDeviceInteractive; @@ -4285,7 +4379,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @Inject NotificationListener mNotificationListener; + private final NotificationListener mNotificationListener; public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) { if (snoozeOption.getSnoozeCriterion() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index cd1f0cc13297..47b56e097ec9 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -92,7 +92,7 @@ public class UsbPermissionActivity extends AlertActivity mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory); } else { boolean hasRecordPermission = - PermissionChecker.checkPermission( + PermissionChecker.checkPermissionForPreflight( this, android.Manifest.permission.RECORD_AUDIO, -1, aInfo.uid, mPackageName) == android.content.pm.PackageManager.PERMISSION_GRANTED; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index ad7bba1e0790..57b09872f9c1 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; @@ -481,6 +482,25 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.isUserUnlocked(randomUser)).isFalse(); } + @Test + public void testTrustUsuallyManaged_whenTrustChanges() { + int user = KeyguardUpdateMonitor.getCurrentUser(); + when(mTrustManager.isTrustUsuallyManaged(eq(user))).thenReturn(true); + mKeyguardUpdateMonitor.onTrustManagedChanged(false /* managed */, user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isTrue(); + } + + @Test + public void testTrustUsuallyManaged_resetWhenUserIsRemoved() { + int user = KeyguardUpdateMonitor.getCurrentUser(); + when(mTrustManager.isTrustUsuallyManaged(eq(user))).thenReturn(true); + mKeyguardUpdateMonitor.onTrustManagedChanged(false /* managed */, user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isTrue(); + + mKeyguardUpdateMonitor.handleUserRemoved(user); + assertThat(mKeyguardUpdateMonitor.isTrustUsuallyManaged(user)).isFalse(); + } + private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) { int subscription = simInited ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 30e02e6b46d2..52f7e679b49c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -41,7 +41,6 @@ import android.app.ActivityManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.Context; import android.content.Intent; import android.graphics.drawable.Icon; import android.os.Handler; @@ -145,8 +144,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase { private class TestableNotificationEntryManager extends NotificationEntryManager { private final CountDownLatch mCountDownLatch; - TestableNotificationEntryManager(Context context) { - super(context); + TestableNotificationEntryManager() { + super(new NotificationData(mock(NotificationSectionsFeatureManager.class))); mCountDownLatch = new CountDownLatch(1); } @@ -250,7 +249,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntry.expandedIcon = mock(StatusBarIconView.class); - mEntryManager = new TestableNotificationEntryManager(mContext); + mEntryManager = new TestableNotificationEntryManager(); Dependency.get(InitController.class).executePostInitTasks(); mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager); mEntryManager.addNotificationEntryListener(mEntryListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java index 8d496a72e3b2..6d275419ee94 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java @@ -46,6 +46,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; +import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.Before; import org.junit.Test; @@ -73,7 +74,9 @@ public class NotificationListControllerTest extends SysuiTestCase { private DeviceProvisionedListener mProvisionedListener; // TODO: Remove this once EntryManager no longer needs to be mocked - private NotificationData mNotificationData = new NotificationData(mContext); + private NotificationData mNotificationData = + new NotificationData(new NotificationSectionsFeatureManager( + new DeviceConfigProxyFake(), mContext)); private int mNextNotifId = 0; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt new file mode 100644 index 000000000000..b3d0d22445b6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification + +import android.provider.DeviceConfig +import android.provider.Settings +import android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL +import android.testing.AndroidTestingRunner + +import androidx.test.filters.SmallTest + +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.DeviceConfigProxyFake + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class NotificationSectionsFeatureManagerTest : SysuiTestCase() { + var manager: NotificationSectionsFeatureManager? = null + val proxyFake = DeviceConfigProxyFake() + + @Before + public fun setup() { + Settings.Secure.putInt(mContext.getContentResolver(), + NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) + manager = NotificationSectionsFeatureManager(proxyFake, mContext) + manager!!.clearCache() + } + + @Test + public fun testPeopleFilteringOff_newInterruptionModelOn() { + proxyFake.setProperty( + DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "false", false) + + assertFalse("People filtering should be disabled", manager!!.isFilteringEnabled()) + assertTrue("Expecting 2 buckets when people filtering is disabled", + manager!!.getNumberOfBuckets() == 2) + } + + @Test + public fun testPeopleFilteringOn_newInterruptionModelOn() { + proxyFake.setProperty( + DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false) + + assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled()) + assertTrue("Expecting 3 buckets when people filtering is enabled", + manager!!.getNumberOfBuckets() == 3) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java index 657ec61dfd11..5fbacb1d7adf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java @@ -50,7 +50,6 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Person; -import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; @@ -78,6 +77,7 @@ import com.android.systemui.statusbar.NotificationEntryBuilder; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -139,7 +139,8 @@ public class NotificationDataTest extends SysuiTestCase { mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment); when(mEnvironment.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); - mNotificationData = new TestableNotificationData(mContext); + mNotificationData = new TestableNotificationData( + mock(NotificationSectionsFeatureManager.class)); mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class)); mRow = new NotificationTestHelper(getContext()).createRow(); Dependency.get(InitController.class).executePostInitTasks(); @@ -631,8 +632,8 @@ public class NotificationDataTest extends SysuiTestCase { } public static class TestableNotificationData extends NotificationData { - public TestableNotificationData(Context context) { - super(context); + public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) { + super(sectionsFeatureManager); } public static final String OVERRIDE_RANK = "r"; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index addceb5def6e..3f467eae1d57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -32,10 +32,12 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationTestHelper; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.util.DeviceConfigProxy; import org.junit.Assert; import org.junit.Before; @@ -64,7 +66,9 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mRoundnessManager = new NotificationRoundnessManager(mBypassController, mContext); + mRoundnessManager = new NotificationRoundnessManager( + mBypassController, + new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext)); com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); NotificationTestHelper testHelper = new NotificationTestHelper(getContext()); mFirst = testHelper.createRow(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 31054260eb15..11ae0cc34787 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -55,7 +55,6 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -65,6 +64,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationData; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -79,6 +79,7 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.DeviceConfigProxyFake; import org.junit.After; import org.junit.Before; @@ -144,11 +145,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mDependency.injectMockDependency(ShadeController.class); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - mEntryManager = new TestableNotificationEntryManager(mContext); + mEntryManager = new TestableNotificationEntryManager(mNotificationData); mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); Dependency.get(InitController.class).executePostInitTasks(); - mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager, - mNotificationData); + mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager); NotificationShelf notificationShelf = mock(NotificationShelf.class); @@ -166,7 +166,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mock(SysuiStatusBarStateController.class), mHeadsUpManager, mKeyguardBypassController, - new FalsingManagerFake()); + new FalsingManagerFake(), + new NotificationSectionsFeatureManager(new DeviceConfigProxyFake(), mContext)); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelf(notificationShelf); mStackScroller.setStatusBar(mBar); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 3ba3e281dc81..cb87d7d842a4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -89,6 +89,8 @@ public class KeyguardBouncerTest extends SysuiTestCase { private KeyguardBypassController mKeyguardBypassController; @Mock private Handler mHandler; + @Mock + private KeyguardSecurityModel mKeyguardSecurityModel; private KeyguardBouncer mBouncer; @@ -97,6 +99,9 @@ public class KeyguardBouncerTest extends SysuiTestCase { com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); MockitoAnnotations.initMocks(this); mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); + mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel); + when(mKeyguardSecurityModel.getSecurityMode(anyInt())) + .thenReturn(KeyguardSecurityModel.SecurityMode.None); DejankUtils.setImmediate(true); final ViewGroup container = new FrameLayout(getContext()); when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver); @@ -306,14 +311,6 @@ public class KeyguardBouncerTest extends SysuiTestCase { } @Test - public void testNeedsFullscreenBouncer_asksKeyguardView() { - mBouncer.ensureView(); - mBouncer.needsFullscreenBouncer(); - verify(mKeyguardHostView).getSecurityMode(); - verify(mKeyguardHostView, never()).getCurrentSecurityMode(); - } - - @Test public void testIsFullscreenBouncer_asksKeyguardView() { mBouncer.ensureView(); mBouncer.isFullscreenBouncer(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index f163886193b4..2631ced77972 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -65,7 +65,7 @@ import android.view.ViewGroup.LayoutParams; import androidx.test.filters.SmallTest; -import com.android.internal.logging.MetricsLogger; +import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.internal.statusbar.IStatusBarService; @@ -89,7 +89,6 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -100,14 +99,15 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; -import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NotifPipelineInitializer; import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -122,10 +122,14 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -144,6 +148,15 @@ import java.util.HashSet; @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) public class StatusBarTest extends SysuiTestCase { + + private StatusBar mStatusBar; + private FakeMetricsLogger mMetricsLogger; + private PowerManager mPowerManager; + private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private CommandQueue mCommandQueue; + + @Mock private LightBarController mLightBarController; + @Mock private StatusBarIconController mStatusBarIconController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private KeyguardStateController mKeyguardStateController; @Mock private KeyguardIndicationController mKeyguardIndicationController; @@ -158,7 +171,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private BiometricUnlockController mBiometricUnlockController; @Mock private NotificationData mNotificationData; @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; - @Mock private NotificationViewHierarchyManager mViewHierarchyManager; @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationListener mNotificationListener; @Mock private KeyguardViewMediator mKeyguardViewMediator; @@ -185,17 +197,25 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NavigationBarController mNavigationBarController; @Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier; @Mock private SysuiColorExtractor mColorExtractor; + @Mock private ColorExtractor.GradientColors mGradientColors; @Mock private DozeLog mDozeLog; @Mock private PulseExpansionHandler mPulseExpansionHandler; - @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator; @Mock private KeyguardBypassController mKeyguardBypassController; - - private TestableStatusBar mStatusBar; - private FakeMetricsLogger mMetricsLogger; - private PowerManager mPowerManager; - private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; - private CommandQueue mCommandQueue; + @Mock private InjectionInflationController mInjectionInflationController; + @Mock private DynamicPrivacyController mDynamicPrivacyController; + @Mock private NotifPipelineInitializer mNotifPipelineInitializer; + @Mock private ZenModeController mZenModeController; + @Mock private AutoHideController mAutoHideController; + @Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager; + @Mock private UserSwitcherController mUserSwitcherController; + @Mock private NetworkController mNetworkController; + @Mock private VibratorHelper mVibratorHelper; + @Mock private BubbleController mBubbleController; + @Mock private NotificationGroupManager mGroupManager; + @Mock private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper; + @Mock private StatusBarWindowController mStatusBarWindowController; + @Mock private NotificationIconAreaController mNotificationIconAreaController; @Before public void setup() throws Exception { @@ -216,7 +236,7 @@ public class StatusBarTest extends SysuiTestCase { mMetricsLogger = new FakeMetricsLogger(); TestableNotificationEntryManager entryManager = new TestableNotificationEntryManager( - mContext); + mNotificationData); NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, Dependency.get(UiOffloadThread.class), entryManager, mStatusBarStateController, mExpansionStateLogger); @@ -249,69 +269,92 @@ public class StatusBarTest extends SysuiTestCase { mHeadsUpManager, mHeadsUpSuppressor); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); - mStatusBar = new TestableStatusBar( - mStatusBarKeyguardViewManager, - mKeyguardIndicationController, - mStackScroller, - mPowerManager, - mNotificationPanelView, - mBarService, - mNotificationListener, - notificationLogger, - mVisualStabilityManager, - mViewHierarchyManager, - entryManager, - mScrimController, - mBiometricUnlockController, - mKeyguardViewMediator, - mRemoteInputManager, - mock(NotificationGroupManager.class), - mock(NotificationGroupAlertTransferHelper.class), - new FalsingManagerFake(), - mock(StatusBarWindowController.class), - mock(NotificationIconAreaController.class), - mDozeScrimController, - mock(NotificationShelf.class), - mLockscreenUserManager, - mCommandQueue, - mNotificationPresenter, - mock(BubbleController.class), - mNavigationBarController, - mock(AutoHideController.class), + + WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle(); + wakefulnessLifecycle.dispatchStartedWakingUp(); + wakefulnessLifecycle.dispatchFinishedWakingUp(); + + when(mGradientColors.supportsDarkText()).thenReturn(true); + when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + ConfigurationController configurationController = new ConfigurationControllerImpl(mContext); + + mStatusBar = new StatusBar( + mLightBarController, + mAutoHideController, mKeyguardUpdateMonitor, - mStatusBarWindowView, + mStatusBarIconController, + mDozeLog, + mInjectionInflationController, + mPulseExpansionHandler, + mNotificationWakeUpCoordinator, + mKeyguardBypassController, + mKeyguardStateController, + mHeadsUpManager, + mDynamicPrivacyController, + mBypassHeadsUpNotifier, + true, + mNotifPipelineInitializer, + new FalsingManagerFake(), mBroadcastDispatcher, - mAssistManager, + new RemoteInputQuickSettingsDisabler( + mContext, + configurationController + ), mNotificationGutsManager, - mNotificationMediaManager, + notificationLogger, + entryManager, + mNotificationInterruptionStateProvider, + mNotificationViewHierarchyManager, mForegroundServiceController, mAppOpsController, - mStatusBarStateController, - mDeviceProvisionedController, + mKeyguardViewMediator, + mZenModeController, mNotificationAlertingManager, - mNotificationInterruptionStateProvider, - mMetricsLogger, - mHeadsUpManager, - mKeyguardStateController, - new ScreenLifecycle(), - mBypassHeadsUpNotifier, - mColorExtractor, new DisplayMetrics(), + mMetricsLogger, Dependency.get(UiOffloadThread.class), - mDozeLog, - mPulseExpansionHandler, - new RemoteInputQuickSettingsDisabler( - mContext, - new ConfigurationControllerImpl(mContext) - ), - mNotificationWakeUpCoordinator, - mKeyguardBypassController); + mNotificationMediaManager, + mLockscreenUserManager, + mRemoteInputManager, + mUserSwitcherController, + mNetworkController, + mBatteryController, + mColorExtractor, + new ScreenLifecycle(), + wakefulnessLifecycle, + mStatusBarStateController, + mVibratorHelper, + mBubbleController, + mGroupManager, + mGroupAlertTransferHelper, + mVisualStabilityManager, + mDeviceProvisionedController, + mNavigationBarController, + mAssistManager, + mNotificationListener, + configurationController, + mStatusBarWindowController); + // TODO: we should be able to call mStatusBar.start() and have all the below values + // initialized automatically. mStatusBar.mContext = mContext; mStatusBar.mComponents = mContext.getComponents(); + mStatusBar.mStatusBarKeyguardViewManager = mStatusBarKeyguardViewManager; + mStatusBar.mStatusBarWindow = mStatusBarWindowView; + mStatusBar.mBiometricUnlockController = mBiometricUnlockController; + mStatusBar.mScrimController = mScrimController; + mStatusBar.mNotificationPanel = mNotificationPanelView; + mStatusBar.mCommandQueue = mCommandQueue; + mStatusBar.mDozeScrimController = mDozeScrimController; + mStatusBar.mNotificationIconAreaController = mNotificationIconAreaController; + mStatusBar.mPresenter = mNotificationPresenter; + mStatusBar.mKeyguardIndicationController = mKeyguardIndicationController; + mStatusBar.mPowerManager = mPowerManager; + mStatusBar.mBarService = mBarService; + mStatusBar.mStackScroller = mStackScroller; mStatusBar.putComponent(StatusBar.class, mStatusBar); Dependency.get(InitController.class).executePostInitTasks(); entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller, - mHeadsUpManager, mNotificationData); + mHeadsUpManager); entryManager.addNotificationEntryListener(mEntryListener); notificationLogger.setUpWithContainer(mStackScroller); } @@ -636,8 +679,8 @@ public class StatusBarTest extends SysuiTestCase { @Test @RunWithLooper(setAsMainLooper = true) public void testUpdateKeyguardState_DoesNotCrash() { - mStatusBar.mState = StatusBarState.KEYGUARD; - when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn( + mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); + when(mLockscreenUserManager.getCurrentProfiles()).thenReturn( new SparseArray<>()); mStatusBar.onStateChanged(StatusBarState.SHADE); } @@ -768,8 +811,7 @@ public class StatusBarTest extends SysuiTestCase { verify(mStatusBarStateController).setState(eq(StatusBarState.KEYGUARD)); // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER. - mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class); - when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); + when(mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true); mStatusBar.showKeyguardImpl(); verify(mStatusBarStateController).setState(eq(StatusBarState.FULLSCREEN_USER_SWITCHER)); } @@ -821,155 +863,23 @@ public class StatusBarTest extends SysuiTestCase { any(UserHandle.class)); } - static class TestableStatusBar extends StatusBar { - public TestableStatusBar(StatusBarKeyguardViewManager man, - KeyguardIndicationController key, - NotificationStackScrollLayout stack, - PowerManager pm, NotificationPanelView panelView, - IStatusBarService barService, NotificationListener notificationListener, - NotificationLogger notificationLogger, - VisualStabilityManager visualStabilityManager, - NotificationViewHierarchyManager viewHierarchyManager, - TestableNotificationEntryManager entryManager, ScrimController scrimController, - BiometricUnlockController biometricUnlockController, - KeyguardViewMediator keyguardViewMediator, - NotificationRemoteInputManager notificationRemoteInputManager, - NotificationGroupManager notificationGroupManager, - NotificationGroupAlertTransferHelper notificationGroupAlertTransferHelper, - FalsingManager falsingManager, - StatusBarWindowController statusBarWindowController, - NotificationIconAreaController notificationIconAreaController, - DozeScrimController dozeScrimController, - NotificationShelf notificationShelf, - NotificationLockscreenUserManager notificationLockscreenUserManager, - CommandQueue commandQueue, - StatusBarNotificationPresenter notificationPresenter, - BubbleController bubbleController, - NavigationBarController navBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarWindowView statusBarWindow, - BroadcastDispatcher broadcastDispatcher, - AssistManager assistManager, - NotificationGutsManager notificationGutsManager, - NotificationMediaManager notificationMediaManager, - ForegroundServiceController foregroundServiceController, - AppOpsController appOpsController, - SysuiStatusBarStateController statusBarStateController, - DeviceProvisionedController deviceProvisionedController, - NotificationAlertingManager notificationAlertingManager, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, - MetricsLogger metricsLogger, - HeadsUpManagerPhone headsUpManager, - KeyguardStateController keyguardStateController, - ScreenLifecycle screenLifecycle, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - SysuiColorExtractor colorExtractor, DisplayMetrics displayMetrics, - UiOffloadThread uiOffloadThread, - DozeLog dozeLog, - PulseExpansionHandler pulseExpansionHandler, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController) { - mStatusBarKeyguardViewManager = man; - mKeyguardIndicationController = key; - mStackScroller = stack; - mPowerManager = pm; - mNotificationPanel = panelView; - mBarService = barService; - mNotificationListener = notificationListener; - mNotificationLogger = notificationLogger; - mWakefulnessLifecycle = createAwakeWakefulnessLifecycle(); - mVisualStabilityManager = visualStabilityManager; - mViewHierarchyManager = viewHierarchyManager; - mEntryManager = entryManager; - mScrimController = scrimController; - mBiometricUnlockController = biometricUnlockController; - mKeyguardViewMediator = keyguardViewMediator; - mRemoteInputManager = notificationRemoteInputManager; - mGroupManager = notificationGroupManager; - mGroupAlertTransferHelper = notificationGroupAlertTransferHelper; - mFalsingManager = falsingManager; - mStatusBarWindowController = statusBarWindowController; - mNotificationIconAreaController = notificationIconAreaController; - mDozeScrimController = dozeScrimController; - mNotificationShelf = notificationShelf; - mLockscreenUserManager = notificationLockscreenUserManager; - mCommandQueue = commandQueue; - mPresenter = notificationPresenter; - mGestureWakeLock = mock(PowerManager.WakeLock.class); - mBubbleController = bubbleController; - mNavigationBarController = navBarController; - mAutoHideController = autoHideController; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mStatusBarWindow = statusBarWindow; - mDozeServiceHost.mWakeLockScreenPerformsAuth = false; - mBroadcastDispatcher = broadcastDispatcher; - mAssistManager = assistManager; - mGutsManager = notificationGutsManager; - mMediaManager = notificationMediaManager; - mForegroundServiceController = foregroundServiceController; - mAppOpsController = appOpsController; - mStatusBarStateController = statusBarStateController; - mDeviceProvisionedController = deviceProvisionedController; - mNotificationAlertingManager = notificationAlertingManager; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; - mMetricsLogger = metricsLogger; - mHeadsUpManager = headsUpManager; - mKeyguardStateController = keyguardStateController; - mScreenLifecycle = screenLifecycle; - mBypassHeadsUpNotifier = bypassHeadsUpNotifier; - mColorExtractor = colorExtractor; - mDisplayMetrics = displayMetrics; - mUiOffloadThread = uiOffloadThread; - mDozeLog = dozeLog; - mPulseExpansionHandler = pulseExpansionHandler; - mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; - mWakeUpCoordinator = notificationWakeUpCoordinator; - mKeyguardBypassController = keyguardBypassController; - } - - private WakefulnessLifecycle createAwakeWakefulnessLifecycle() { - WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle(); - wakefulnessLifecycle.dispatchStartedWakingUp(); - wakefulnessLifecycle.dispatchFinishedWakingUp(); - return wakefulnessLifecycle; - } - - @Override - protected void updateTheme() { - // Do nothing for now, until we have more mocking and StatusBar is smaller. - } - - public void setBarStateForTest(int state) { - mState = state; - } - - public void setUserSetupForTest(boolean userSetup) { - mUserSetup = userSetup; - } - - } - public static class TestableNotificationEntryManager extends NotificationEntryManager { - public TestableNotificationEntryManager(Context context) { - super(context); + public TestableNotificationEntryManager(NotificationData notificationData) { + super(notificationData); } public void setUpForTest(NotificationPresenter presenter, NotificationListContainer listContainer, - HeadsUpManagerPhone headsUpManager, - NotificationData notificationData) { + HeadsUpManagerPhone headsUpManager) { super.setUpWithPresenter(presenter, listContainer, headsUpManager); - mNotificationData = notificationData; } } public static class TestableNotificationInterruptionStateProvider extends NotificationInterruptionStateProvider { - public TestableNotificationInterruptionStateProvider( + TestableNotificationInterruptionStateProvider( Context context, PowerManager powerManager, IDreamManager dreamManager, diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 4f021ad3cee0..514eb77c3201 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -350,9 +350,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ protected abstract boolean hasRightsToCurrentUserLocked(); + @Nullable @Override - public List<AccessibilityWindowInfo> getWindows() { - ensureWindowsAvailableTimed(Display.DEFAULT_DISPLAY); + public AccessibilityWindowInfo.WindowListSparseArray getWindows() { synchronized (mLock) { if (!hasRightsToCurrentUserLocked()) { return null; @@ -362,38 +362,39 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (!permissionGranted) { return null; } - List<AccessibilityWindowInfo> internalWindowList = - mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); - if (internalWindowList == null) { - return null; - } if (!mSecurityPolicy.checkAccessibilityAccess(this)) { return null; } - List<AccessibilityWindowInfo> returnedWindowList = new ArrayList<>(); - final int windowCount = internalWindowList.size(); - for (int i = 0; i < windowCount; i++) { - AccessibilityWindowInfo window = internalWindowList.get(i); - AccessibilityWindowInfo windowClone = - AccessibilityWindowInfo.obtain(window); - windowClone.setConnectionId(mId); - returnedWindowList.add(windowClone); + final AccessibilityWindowInfo.WindowListSparseArray allWindows = + new AccessibilityWindowInfo.WindowListSparseArray(); + final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(); + final int displayListCounts = displayList.size(); + if (displayListCounts > 0) { + for (int i = 0; i < displayListCounts; i++) { + final int displayId = displayList.get(i); + ensureWindowsAvailableTimedLocked(displayId); + + final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked( + displayId); + if (windowList != null) { + allWindows.put(displayId, windowList); + } + } } - return returnedWindowList; + return allWindows; } } @Override public AccessibilityWindowInfo getWindow(int windowId) { - int displayId = Display.INVALID_DISPLAY; synchronized (mLock) { + int displayId = Display.INVALID_DISPLAY; if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked( mSystemSupport.getCurrentUserIdLocked(), windowId); } - } - ensureWindowsAvailableTimed(displayId); - synchronized (mLock) { + ensureWindowsAvailableTimedLocked(displayId); + if (!hasRightsToCurrentUserLocked()) { return null; } @@ -1316,35 +1317,33 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ * * @param displayId The logical display id. */ - private void ensureWindowsAvailableTimed(int displayId) { - synchronized (mLock) { - if (mA11yWindowManager.getWindowListLocked(displayId) != null) { - return; - } - // If we have no registered callback, update the state we - // we may have to register one but it didn't happen yet. - if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { - // Invokes client change to make sure tracking window enabled. - mSystemSupport.onClientChangeLocked(false); - } - // We have no windows but do not care about them, done. - if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { + private void ensureWindowsAvailableTimedLocked(int displayId) { + if (mA11yWindowManager.getWindowListLocked(displayId) != null) { + return; + } + // If we have no registered callback, update the state we + // we may have to register one but it didn't happen yet. + if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { + // Invokes client change to make sure tracking window enabled. + mSystemSupport.onClientChangeLocked(false); + } + // We have no windows but do not care about them, done. + if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { + return; + } + + // Wait for the windows with a timeout. + final long startMillis = SystemClock.uptimeMillis(); + while (mA11yWindowManager.getWindowListLocked(displayId) == null) { + final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; + final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis; + if (remainMillis <= 0) { return; } - - // Wait for the windows with a timeout. - final long startMillis = SystemClock.uptimeMillis(); - while (mA11yWindowManager.getWindowListLocked(displayId) == null) { - final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; - final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis; - if (remainMillis <= 0) { - return; - } - try { - mLock.wait(remainMillis); - } catch (InterruptedException ie) { - /* ignore */ - } + try { + mLock.wait(remainMillis); + } catch (InterruptedException ie) { + /* ignore */ } } } @@ -1442,6 +1441,24 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ interrogatingPid, interrogatingTid); } + private List<AccessibilityWindowInfo> getWindowsByDisplayLocked(int displayId) { + final List<AccessibilityWindowInfo> internalWindowList = + mA11yWindowManager.getWindowListLocked(displayId); + if (internalWindowList == null) { + return null; + } + final List<AccessibilityWindowInfo> returnedWindowList = new ArrayList<>(); + final int windowCount = internalWindowList.size(); + for (int i = 0; i < windowCount; i++) { + AccessibilityWindowInfo window = internalWindowList.get(i); + AccessibilityWindowInfo windowClone = + AccessibilityWindowInfo.obtain(window); + windowClone.setConnectionId(mId); + returnedWindowList.add(windowClone); + } + return returnedWindowList; + } + public ComponentName getComponentName() { return mComponentName; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index 0038a27db384..cb858ac11b00 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -1472,11 +1472,27 @@ public class AccessibilityWindowManager { public int getDisplayIdByUserIdAndWindowIdLocked(int userId, int windowId) { final IBinder windowToken = getWindowTokenForUserAndWindowIdLocked(userId, windowId); final int displayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken); - return displayId; } /** + * Returns the display list including all displays which are tracking windows. + * + * @return The display list. + */ + public ArrayList<Integer> getDisplayListLocked() { + final ArrayList<Integer> displayList = new ArrayList<>(); + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + displayList.add(observer.mDisplayId); + } + } + return displayList; + } + + /** * Gets current input focused window token from window manager, and returns its windowId. * * @param userId The userId diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java index 7e8fb295d036..3dfe59e142a6 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/AccessibilityGestureDetector.java @@ -408,9 +408,6 @@ class AccessibilityGestureDetector extends GestureDetector.SimpleOnGestureListen cancelGesture(); } - public boolean firstTapDetected() { - return mFirstTapDetected; - } @Override public void onLongPress(MotionEvent e) { diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index c60e35e2cc6d..b62e260aacad 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -411,24 +411,12 @@ public class TouchExplorer extends BaseEventStreamTransformation // we resent the delayed callback and wait again. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); - // If a touch exploration gesture is in progress send events for its end. if (mState.isTouchExploring()) { sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } - // Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double - // tap. - if (!mGestureDetector.firstTapDetected() && mState.isClear()) { - mSendTouchExplorationEndDelayed.forceSendAndRemove(); - mSendTouchInteractionEndDelayed.forceSendAndRemove(); - mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START); - } else { - // Let gesture to handle to avoid duplicated TYPE_TOUCH_INTERACTION_END event. - mSendTouchInteractionEndDelayed.cancel(); - } - - if (!mGestureDetector.firstTapDetected() && !mState.isTouchExploring()) { + if (mState.isClear()) { if (!mSendHoverEnterAndMoveDelayed.isPending()) { // Queue a delayed transition to STATE_TOUCH_EXPLORING. // If we do not detect that this is a gesture, delegation or drag the transition @@ -441,6 +429,12 @@ public class TouchExplorer extends BaseEventStreamTransformation // Cache the event until we discern exploration from gesturing. mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent); } + mSendTouchExplorationEndDelayed.forceSendAndRemove(); + mSendTouchInteractionEndDelayed.forceSendAndRemove(); + mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START); + } else { + // Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double tap. + mSendTouchInteractionEndDelayed.cancel(); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ee98af4020ad..7cbd1fcebb94 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9736,6 +9736,10 @@ public class ActivityManagerService extends IActivityManager.Stub sb.append("Foreground: ") .append(process.isInterestingToUserLocked() ? "Yes" : "No") .append("\n"); + if (process.startTime > 0) { + long runtimeMillis = SystemClock.elapsedRealtime() - process.startTime; + sb.append("Process-Runtime: ").append(runtimeMillis).append("\n"); + } } if (activityShortComponentName != null) { sb.append("Activity: ").append(activityShortComponentName).append("\n"); diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING index 21d4925722d0..bc4707f04724 100644 --- a/services/core/java/com/android/server/am/TEST_MAPPING +++ b/services/core/java/com/android/server/am/TEST_MAPPING @@ -33,7 +33,6 @@ }, { "name": "FrameworksMockingServicesTests", - "file_patterns": ["AppCompactor\\.java"], "options": [ { "include-filter": "com.android.server.am." diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 8e4474c462ab..175419117898 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1184,7 +1184,7 @@ class UserController implements Handler.Callback { updateStartedUserArrayLU(); } needStart = true; - t.traceBegin("updateStateStopping"); + t.traceEnd(); } if (uss.state == UserState.STATE_BOOTING) { diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 8e09d0e5958e..852b26d1ff07 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -47,7 +47,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public void reportChange(long changeId, ApplicationInfo appInfo) { - reportChange(changeId, appInfo, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + reportChange(changeId, appInfo.uid, + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); } @Override @@ -60,13 +61,18 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void reportChangeByUid(long changeId, int uid) { + reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED); + } + + @Override public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) { if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) { - reportChange(changeId, appInfo, + reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); return true; } - reportChange(changeId, appInfo, + reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED); return false; } @@ -81,6 +87,19 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public boolean isChangeEnabledByUid(long changeId, int uid) { + String[] packages = mContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + return true; + } + boolean enabled = true; + for (String packageName : packages) { + enabled = enabled && isChangeEnabledByPackageName(changeId, packageName); + } + return enabled; + } + + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; CompatConfig.get().dumpConfig(pw); @@ -95,8 +114,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { return null; } - private void reportChange(long changeId, ApplicationInfo appInfo, int state) { - int uid = appInfo.uid; + private void reportChange(long changeId, int uid, int state) { mChangeReporter.reportChange(uid, changeId, state); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 4f4baab204e6..61d4d4bf9ac1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -850,36 +850,25 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { mAddress, Constants.ADDR_BROADCAST, systemAudioStatusOn)); if (systemAudioStatusOn) { + // If TV sends out SAM Request with a path of a non-CEC device, which should not show + // up in the CEC device list and not under the current AVR device, the AVR would switch + // to ARC. int sourcePhysicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); - if (sourcePhysicalAddress != getActiveSource().physicalAddress) { - // If the Active Source recorded by the current device is not synced up with TV, - // update the Active Source internally. - if (sourcePhysicalAddress == mService.getPhysicalAddress()) { - // If the active path is the current device itself, update with local info - if (mService.playback() != null) { - setActiveSource(mService.playback().mAddress, sourcePhysicalAddress); - } else { - setActiveSource(mAddress, sourcePhysicalAddress); - } - } else { - // If it's not the current device, look for the device info from the list - for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) { - if (info.getPhysicalAddress() == sourcePhysicalAddress) { - setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress()); - break; - } - } - } - // If the Active path from TV's System Audio Mode request does not belong to any - // device in the local device list, record the new Active physicalAddress with an - // unregistered logical address first. Then query the Active Source again. - if (sourcePhysicalAddress != getActiveSource().physicalAddress) { - setActiveSource(Constants.ADDR_UNREGISTERED, sourcePhysicalAddress); - mService.sendCecCommand( - HdmiCecMessageBuilder.buildRequestActiveSource(mAddress)); + if (HdmiUtils.getLocalPortFromPhysicalAddress( + sourcePhysicalAddress, getDeviceInfo().getPhysicalAddress()) + != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE) { + return true; + } + boolean isDeviceInCecDeviceList = false; + for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) { + if (info.getPhysicalAddress() == sourcePhysicalAddress) { + isDeviceInCecDeviceList = true; + break; } } - switchInputOnReceivingNewActivePath(sourcePhysicalAddress); + if (!isDeviceInCecDeviceList) { + switchInputOnReceivingNewActivePath(sourcePhysicalAddress); + } } return true; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index c3354e1d7e0f..1794df3b602e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -311,6 +311,11 @@ public class HdmiControlService extends SystemService { private IHdmiControlCallback mDisplayStatusCallback = null; @Nullable + // Save callback when the device is still under logcial address allocation + // Invoke once new local device is ready. + private IHdmiControlCallback mOtpCallbackPendingAddressAllocation = null; + + @Nullable private HdmiCecController mCecController; // HDMI port information. Stored in the unmodifiable list to keep the static information @@ -785,17 +790,21 @@ public class HdmiControlService extends SystemService { // Address allocation completed for all devices. Notify each device. if (allocatingDevices.size() == ++finished[0]) { mAddressAllocated = true; - // Reinvoke the saved display status callback once the local device is ready. - if (mDisplayStatusCallback != null) { - queryDisplayStatus(mDisplayStatusCallback); - mDisplayStatusCallback = null; - } if (initiatedBy != INITIATED_BY_HOTPLUG) { // In case of the hotplug we don't call onInitializeCecComplete() // since we reallocate the logical address only. onInitializeCecComplete(initiatedBy); } notifyAddressAllocated(allocatedDevices, initiatedBy); + // Reinvoke the saved display status callback once the local device is ready. + if (mDisplayStatusCallback != null) { + queryDisplayStatus(mDisplayStatusCallback); + mDisplayStatusCallback = null; + } + if (mOtpCallbackPendingAddressAllocation != null) { + oneTouchPlay(mOtpCallbackPendingAddressAllocation); + mOtpCallbackPendingAddressAllocation = null; + } mCecMessageBuffer.processMessages(); } } @@ -2246,8 +2255,16 @@ public class HdmiControlService extends SystemService { } @ServiceThreadOnly - private void oneTouchPlay(final IHdmiControlCallback callback) { + @VisibleForTesting + protected void oneTouchPlay(final IHdmiControlCallback callback) { assertRunOnServiceThread(); + if (!mAddressAllocated) { + mOtpCallbackPendingAddressAllocation = callback; + Slog.d(TAG, "Local device is under address allocation. " + + "Save OTP callback for later process."); + return; + } + HdmiCecLocalDeviceSource source = playback(); if (source == null) { source = audioSystem(); diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index c8fc5fc96e59..4962af176f18 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -77,7 +77,6 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress)); broadcastActiveSource(); queryDevicePowerStatus(); - mState = STATE_WAITING_FOR_REPORT_POWER_STATUS; addTimer(mState, HdmiConfig.TIMEOUT_MS); return true; } @@ -99,6 +98,7 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { } private void queryDevicePowerStatus() { + mState = STATE_WAITING_FOR_REPORT_POWER_STATUS; sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), mTargetAddress)); } diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING new file mode 100644 index 000000000000..b45b4eaa1ba7 --- /dev/null +++ b/services/core/java/com/android/server/integrity/TEST_MAPPING @@ -0,0 +1,18 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.integrity." + }, + { + "include-annotation": "android.platform.test.annotations.Presubmit" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ] + } + ] +} diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java new file mode 100644 index 000000000000..fc4430640b90 --- /dev/null +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.engine; + +import com.android.server.integrity.model.Rule; + +import java.util.ArrayList; +import java.util.List; + +/** + * The engine used to evaluate rules against app installs. + * + * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine + * to allow/block that install. + */ +public final class RuleEvaluationEngine { + private static final String TAG = "RuleEvaluation"; + + // The engine for loading rules, retrieving metadata for app installs, and evaluating app + // installs against rules. + private static RuleEvaluationEngine sRuleEvaluationEngine; + + // The subset of rules loaded to be used to evaluate an app install request. + // TODO: Load rules relevant to app installs. + private List<Rule> mRules; + + private RuleEvaluationEngine() { + // Initialize rules with the empty rule set. + mRules = new ArrayList<>(); + } + + /** + * Provide a singleton instance of the rule evaluation engine. + */ + public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() { + if (sRuleEvaluationEngine == null) { + return new RuleEvaluationEngine(); + } + return sRuleEvaluationEngine; + } +} diff --git a/services/core/java/com/android/server/integrity/engine/RuleLoader.java b/services/core/java/com/android/server/integrity/engine/RuleLoader.java new file mode 100644 index 000000000000..af24d7a21dc8 --- /dev/null +++ b/services/core/java/com/android/server/integrity/engine/RuleLoader.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.engine; + +import com.android.server.integrity.model.Rule; + +import java.util.ArrayList; +import java.util.List; + +/** + * A helper class for loading rules to the rule evaluation engine. + * + * <p>Expose fine-grained APIs for loading rules to be passed to the rule evaluation engine. + * + * <p>It supports: + * <ul> + * <li>Loading rules based on some keys, such as PACKAGE_NAME and APP_CERT.</li> + * </ul> + * + * <p>It does NOT support: + * <ul> + * <li>Loading the list of all rules.</li> + * <li>Merging rules resulting from different APIs.</li> + * </ul> + */ +final class RuleLoader { + + List<Rule> loadRulesByPackageName(String packageName) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByAppCertificate(String appCertificate) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByInstallerName(String installerName) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } + + List<Rule> loadRulesByInstallerCertificate(String installerCertificate) { + // TODO: Add logic based on rule storage. + return new ArrayList<>(); + } +} diff --git a/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java index c2ed3df0ffff..814b8e1d783b 100644 --- a/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java +++ b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.integrity.engine; +package com.android.server.integrity.model; /** * The app install metadata. @@ -32,7 +32,7 @@ public final class AppInstallMetadata { final int mVersionCode; final boolean mIsPreInstalled; - AppInstallMetadata(String packageName, String appCertificate, String installerName, + public AppInstallMetadata(String packageName, String appCertificate, String installerName, String installerCertificate, int versionCode, boolean isPreInstalled) { this.mPackageName = packageName; this.mAppCertificate = appCertificate; diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java new file mode 100644 index 000000000000..a6e08d8504ed --- /dev/null +++ b/services/core/java/com/android/server/integrity/model/Rule.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.model; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; + +/** + * Represent rules to be used in the rule evaluation engine to match against app installs. + * + * <p>Instances of this class are immutable. + */ +public final class Rule { + + // Holds an empty rule instance. + public static final Rule EMPTY = new Rule(); + + enum Key { + PACKAGE_NAME, + APP_CERTIFICATE, + INSTALLER_NAME, + INSTALLER_CERTIFICATE, + VERSION_CODE, + PRE_INSTALLED + } + + enum Effect { + DENY + } + + enum Operator { + EQ, + LT, + LE, + GT, + GE + } + + enum Connector { + AND, + OR, + NOT + } + + private final Formula mFormula; + private final Effect mEffect; + + private Rule() { + this.mFormula = null; + this.mEffect = null; + } + + public Rule(Formula formula, Effect effect) { + this.mFormula = checkNotNull(formula); + this.mEffect = checkNotNull(effect); + } + + /** + * Indicates whether the rule is empty or not. + * + * @return {@code true} if the rule is empty, and {@code false} otherwise. + */ + public boolean isEmpty() { + return mFormula == null && mEffect == null; + } + + public Formula getFormula() { + return mFormula; + } + + public Effect getEffect() { + return mEffect; + } + + // TODO: Consider moving the sub-components to their respective model class. + + /** + * Represents a rule logic/content. + */ + abstract static class Formula { + + } + + /** + * Represents a simple formula consisting of an app install metadata field and a value. + */ + public static final class AtomicFormula extends Formula { + + final Key mKey; + final Operator mOperator; + + // The value of a key can take either 1 of 3 forms: String, Integer, or Boolean. + // It cannot have multiple values. + @Nullable + final String mStringValue; + @Nullable + final Integer mIntValue; + @Nullable + final Boolean mBoolValue; + + public AtomicFormula(Key key, Operator operator, String stringValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = stringValue; + this.mIntValue = null; + this.mBoolValue = null; + } + + public AtomicFormula(Key key, Operator operator, Integer intValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = null; + this.mIntValue = intValue; + this.mBoolValue = null; + } + + public AtomicFormula(Key key, Operator operator, Boolean boolValue) { + // TODO: Add validators + this.mKey = key; + this.mOperator = operator; + this.mStringValue = null; + this.mIntValue = null; + this.mBoolValue = boolValue; + } + } + + /** + * Represents a complex formula consisting of other simple and complex formulas. + */ + public static final class OpenFormula extends Formula { + + final Connector mConnector; + final Formula mMainFormula; + final Formula mAuxiliaryFormula; + + public OpenFormula(Connector connector, Formula mainFormula, + @Nullable Formula auxiliaryFormula) { + this.mConnector = checkNotNull(connector); + this.mMainFormula = checkNotNull(mainFormula); + this.mAuxiliaryFormula = auxiliaryFormula; + } + } +} diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 378d9ebdaaa8..bad484fa3807 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -61,7 +61,10 @@ import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; import android.hardware.authsecret.V1_0.IAuthSecret; import android.hardware.biometrics.BiometricManager; +import android.hardware.face.Face; import android.hardware.face.FaceManager; +import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintManager; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -117,6 +120,7 @@ import com.android.internal.widget.LockPatternUtils.CredentialType; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.VerifyCredentialResponse; import com.android.server.LocalServices; +import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.locksettings.LockSettingsStorage.CredentialHash; import com.android.server.locksettings.LockSettingsStorage.PersistentData; @@ -387,8 +391,15 @@ public class LockSettingsService extends ILockSettings.Stub { return mContext; } - public Handler getHandler() { - return new Handler(); + public ServiceThread getServiceThread() { + ServiceThread handlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + true /*allowIo*/); + handlerThread.start(); + return handlerThread; + } + + public Handler getHandler(ServiceThread handlerThread) { + return new Handler(handlerThread.getLooper()); } public LockSettingsStorage getStorage() { @@ -483,6 +494,23 @@ public class LockSettingsService extends ILockSettings.Stub { public boolean isGsiRunning() { return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0; } + + public FingerprintManager getFingerprintManager() { + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { + return (FingerprintManager) mContext.getSystemService(Context.FINGERPRINT_SERVICE); + } else { + return null; + } + } + + public FaceManager getFaceManager() { + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { + return (FaceManager) mContext.getSystemService(Context.FACE_SERVICE); + } else { + return null; + } + } + } public LockSettingsService(Context context) { @@ -495,7 +523,7 @@ public class LockSettingsService extends ILockSettings.Stub { mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore); - mHandler = injector.getHandler(); + mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); mActivityManager = injector.getActivityManager(); @@ -2713,6 +2741,7 @@ public class LockSettingsService extends ILockSettings.Stub { fixateNewestUserKeyAuth(userId); unlockKeystore(auth.deriveKeyStorePassword(), userId); setKeystorePassword(null, userId); + removeBiometricsForUser(userId); } setSyntheticPasswordHandleLocked(newHandle, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); @@ -2728,6 +2757,85 @@ public class LockSettingsService extends ILockSettings.Stub { return newHandle; } + private void removeBiometricsForUser(int userId) { + removeAllFingerprintForUser(userId); + removeAllFaceForUser(userId); + } + + private void removeAllFingerprintForUser(final int userId) { + FingerprintManager mFingerprintManager = mInjector.getFingerprintManager(); + if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { + if (mFingerprintManager.hasEnrolledFingerprints(userId)) { + mFingerprintManager.setActiveUser(userId); + CountDownLatch latch = new CountDownLatch(1); + // For the purposes of M and N, groupId is the same as userId. + Fingerprint finger = new Fingerprint(null, userId, 0, 0); + mFingerprintManager.remove(finger, userId, + fingerprintManagerRemovalCallback(latch)); + try { + latch.await(10000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "Latch interrupted when removing fingerprint", e); + } + } + } + } + + private void removeAllFaceForUser(final int userId) { + FaceManager mFaceManager = mInjector.getFaceManager(); + if (mFaceManager != null && mFaceManager.isHardwareDetected()) { + if (mFaceManager.hasEnrolledTemplates(userId)) { + mFaceManager.setActiveUser(userId); + CountDownLatch latch = new CountDownLatch(1); + Face face = new Face(null, 0, 0); + mFaceManager.remove(face, userId, faceManagerRemovalCallback(latch)); + try { + latch.await(10000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "Latch interrupted when removing face", e); + } + } + } + } + + private FingerprintManager.RemovalCallback fingerprintManagerRemovalCallback( + CountDownLatch latch) { + return new FingerprintManager.RemovalCallback() { + @Override + public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence err) { + Slog.e(TAG, String.format( + "Can't remove fingerprint %d in group %d. Reason: %s", + fp.getBiometricId(), fp.getGroupId(), err)); + latch.countDown(); + } + + @Override + public void onRemovalSucceeded(Fingerprint fp, int remaining) { + if (remaining == 0) { + latch.countDown(); + } + } + }; + } + + private FaceManager.RemovalCallback faceManagerRemovalCallback(CountDownLatch latch) { + return new FaceManager.RemovalCallback() { + @Override + public void onRemovalError(Face face, int errMsgId, CharSequence err) { + Slog.e(TAG, String.format("Can't remove face %d. Reason: %s", + face.getBiometricId(), err)); + latch.countDown(); + } + + @Override + public void onRemovalSucceeded(Face face, int remaining) { + if (remaining == 0) { + latch.countDown(); + } + } + }; + } + @GuardedBy("mSpManager") private boolean spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType, byte[] savedCredential, int requestedQuality, int userId, diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING index c1cba5f7f22d..56f5cc034f05 100644 --- a/services/core/java/com/android/server/locksettings/TEST_MAPPING +++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING @@ -1,5 +1,5 @@ { - "presubmit": [ + "presubmit-devicepolicy": [ { "name": "CtsDevicePolicyManagerTestCases", "options": [ diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 043c834230d1..668f2be158c6 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.media.IMediaRouter2Client; import android.media.IMediaRouter2Manager; +import android.media.IMediaRouterClient; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.os.Binder; @@ -86,7 +87,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - registerClientLocked(client, uid, pid, packageName, userId, trusted); + registerClient2Locked(client, uid, pid, packageName, userId, trusted); } } finally { Binder.restoreCallingIdentity(token); @@ -99,7 +100,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - unregisterClientLocked(client, false); + unregisterClient2Locked(client, false); } } finally { Binder.restoreCallingIdentity(token); @@ -155,14 +156,30 @@ class MediaRouter2ServiceImpl { } } - public void setControlCategories(@NonNull IMediaRouter2Client client, + //TODO: What would happen if a media app used MediaRouter and MediaRouter2 simultaneously? + public void setControlCategories(@NonNull IMediaRouterClient client, + @Nullable List<String> categories) { + Objects.requireNonNull(client, "client must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + setControlCategoriesLocked(clientRecord, categories); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void setControlCategories2(@NonNull IMediaRouter2Client client, @Nullable List<String> categories) { Objects.requireNonNull(client, "client must not be null"); final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - setControlCategoriesLocked(client, categories); + ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + setControlCategoriesLocked(clientRecord, categories); } } finally { Binder.restoreCallingIdentity(token); @@ -174,7 +191,7 @@ class MediaRouter2ServiceImpl { final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - selectRoute2Locked(client, route); + selectRoute2Locked(mAllClientRecords.get(client.asBinder()), route); } } finally { Binder.restoreCallingIdentity(token); @@ -193,6 +210,36 @@ class MediaRouter2ServiceImpl { } } + public void registerClient(@NonNull IMediaRouterClient client, @NonNull String packageName) { + Objects.requireNonNull(client, "client must not be null"); + + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); + final int userId = UserHandle.getUserId(uid); + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + registerClient1Locked(client, packageName, userId); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void unregisterClient(@NonNull IMediaRouterClient client) { + Objects.requireNonNull(client, "client must not be null"); + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + unregisterClient1Locked(client); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + //TODO: Review this is handling multi-user properly. void switchUser() { synchronized (mLock) { @@ -217,9 +264,9 @@ class MediaRouter2ServiceImpl { } } - void clientDied(ClientRecord clientRecord) { + void clientDied(Client2Record clientRecord) { synchronized (mLock) { - unregisterClientLocked(clientRecord.mClient, true); + unregisterClient2Locked(clientRecord.mClient, true); } } @@ -229,18 +276,18 @@ class MediaRouter2ServiceImpl { } } - private void registerClientLocked(IMediaRouter2Client client, + private void registerClient2Locked(IMediaRouter2Client client, int uid, int pid, String packageName, int userId, boolean trusted) { final IBinder binder = client.asBinder(); - ClientRecord clientRecord = mAllClientRecords.get(binder); - if (clientRecord == null) { + if (mAllClientRecords.get(binder) == null) { boolean newUser = false; UserRecord userRecord = mUserRecords.get(userId); if (userRecord == null) { userRecord = new UserRecord(userId); newUser = true; } - clientRecord = new ClientRecord(userRecord, client, uid, pid, packageName, trusted); + Client2Record clientRecord = new Client2Record(userRecord, client, uid, pid, + packageName, trusted); try { binder.linkToDeath(clientRecord, 0); } catch (RemoteException ex) { @@ -261,8 +308,8 @@ class MediaRouter2ServiceImpl { } } - private void unregisterClientLocked(IMediaRouter2Client client, boolean died) { - ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); + private void unregisterClient2Locked(IMediaRouter2Client client, boolean died) { + Client2Record clientRecord = (Client2Record) mAllClientRecords.remove(client.asBinder()); if (clientRecord != null) { UserRecord userRecord = clientRecord.mUserRecord; userRecord.mClientRecords.remove(clientRecord); @@ -272,8 +319,7 @@ class MediaRouter2ServiceImpl { } } - private void selectRoute2Locked(IMediaRouter2Client client, MediaRoute2Info route) { - ClientRecord clientRecord = mAllClientRecords.get(client.asBinder()); + private void selectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) { if (clientRecord != null) { MediaRoute2Info oldRoute = clientRecord.mSelectedRoute; clientRecord.mSelectedRoute = route; @@ -294,10 +340,7 @@ class MediaRouter2ServiceImpl { } } - private void setControlCategoriesLocked(IMediaRouter2Client client, List<String> categories) { - final IBinder binder = client.asBinder(); - ClientRecord clientRecord = mAllClientRecords.get(binder); - + private void setControlCategoriesLocked(ClientRecord clientRecord, List<String> categories) { if (clientRecord != null) { clientRecord.mControlCategories = categories; @@ -349,9 +392,7 @@ class MediaRouter2ServiceImpl { obtainMessage(UserHandler::notifyProviderInfosUpdatedToManager, userRecord.mHandler, manager)); - final int count = userRecord.mClientRecords.size(); - for (int i = 0; i < count; i++) { - ClientRecord clientRecord = userRecord.mClientRecords.get(i); + for (ClientRecord clientRecord : userRecord.mClientRecords) { clientRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::updateClientUsage, clientRecord.mUserRecord.mHandler, clientRecord)); @@ -378,7 +419,7 @@ class MediaRouter2ServiceImpl { Slog.w(TAG, "Ignoring route selection for unknown client."); } if (clientRecord != null && managerRecord.mTrusted) { - selectRoute2Locked(clientRecord.mClient, route); + selectRoute2Locked(clientRecord, route); } } } @@ -409,6 +450,37 @@ class MediaRouter2ServiceImpl { } } + private void registerClient1Locked(IMediaRouterClient client, String packageName, + int userId) { + final IBinder binder = client.asBinder(); + if (mAllClientRecords.get(binder) == null) { + boolean newUser = false; + UserRecord userRecord = mUserRecords.get(userId); + if (userRecord == null) { + userRecord = new UserRecord(userId); + newUser = true; + } + ClientRecord clientRecord = new Client1Record(userRecord, client, packageName); + + if (newUser) { + mUserRecords.put(userId, userRecord); + initializeUserLocked(userRecord); + } + + userRecord.mClientRecords.add(clientRecord); + mAllClientRecords.put(binder, clientRecord); + } + } + + private void unregisterClient1Locked(IMediaRouterClient client) { + ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder()); + if (clientRecord != null) { + UserRecord userRecord = clientRecord.mUserRecord; + userRecord.mClientRecords.remove(clientRecord); + disposeUserIfNeededLocked(userRecord); + } + } + final class UserRecord { public final int mUserId; final ArrayList<ClientRecord> mClientRecords = new ArrayList<>(); @@ -430,25 +502,43 @@ class MediaRouter2ServiceImpl { } } - final class ClientRecord implements IBinder.DeathRecipient { + class ClientRecord { public final UserRecord mUserRecord; + public final String mPackageName; + public List<String> mControlCategories; + public MediaRoute2Info mSelectedRoute; + + ClientRecord(UserRecord userRecord, String packageName) { + mUserRecord = userRecord; + mPackageName = packageName; + mControlCategories = Collections.emptyList(); + } + } + + final class Client1Record extends ClientRecord { + public final IMediaRouterClient mClient; + + Client1Record(UserRecord userRecord, IMediaRouterClient client, + String packageName) { + super(userRecord, packageName); + mClient = client; + } + } + + final class Client2Record extends ClientRecord + implements IBinder.DeathRecipient { public final IMediaRouter2Client mClient; public final int mUid; public final int mPid; - public final String mPackageName; public final boolean mTrusted; - public List<String> mControlCategories; - public MediaRoute2Info mSelectedRoute; - ClientRecord(UserRecord userRecord, IMediaRouter2Client client, + Client2Record(UserRecord userRecord, IMediaRouter2Client client, int uid, int pid, String packageName, boolean trusted) { - mUserRecord = userRecord; + super(userRecord, packageName); mClient = client; mUid = uid; mPid = pid; - mPackageName = packageName; mTrusted = trusted; - mControlCategories = Collections.emptyList(); } public void dispose() { @@ -622,7 +712,9 @@ class MediaRouter2ServiceImpl { managers.add(managerRecord.mManager); } for (ClientRecord clientRecord : mUserRecord.mClientRecords) { - clients.add(clientRecord.mClient); + if (clientRecord instanceof Client2Record) { + clients.add(((Client2Record) clientRecord).mClient); + } } } for (IMediaRouter2Manager manager : managers) { diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 2670cd8247ac..796a25d7e295 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -249,6 +249,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted); } + mService2.registerClient(client, packageName); } finally { Binder.restoreCallingIdentity(token); } @@ -289,6 +290,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { unregisterClientLocked(client, false); } + mService2.unregisterClient(client); } finally { Binder.restoreCallingIdentity(token); } @@ -395,6 +397,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void setControlCategories(IMediaRouterClient client, List<String> controlCategories) { + mService2.setControlCategories(client, controlCategories); + } + + // Binder call + @Override public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) { if (client == null) { throw new IllegalArgumentException("client must not be null"); @@ -487,8 +495,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override - public void setControlCategories(IMediaRouter2Client client, List<String> categories) { - mService2.setControlCategories(client, categories); + public void setControlCategories2(IMediaRouter2Client client, List<String> categories) { + mService2.setControlCategories2(client, categories); } void restoreBluetoothA2dp() { @@ -561,6 +569,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub synchronized (mLock) { unregisterClientLocked(clientRecord.mClient, true); } + mService2.unregisterClient(clientRecord.mClient); } private void registerClientLocked(IMediaRouterClient client, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d480cb6e9800..3341991aa0ae 100644..100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -94,7 +94,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; -import static com.android.server.notification.PreferencesHelper.DEFAULT_ALLOW_BUBBLE; import static com.android.server.utils.PriorityDump.PRIORITY_ARG; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL; import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL; @@ -1331,16 +1330,15 @@ public class NotificationManagerService extends SystemService { uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)}; } if (pkgList != null && (pkgList.length > 0)) { - for (String pkgName : pkgList) { - if (cancelNotifications) { + if (cancelNotifications) { + for (String pkgName : pkgList) { cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0, !queryRestart, changeUserId, reason, null); - } else if (hideNotifications) { - hideNotificationsForPackages(pkgList); - } else if (unhideNotifications) { - unhideNotificationsForPackages(pkgList); } - + } else if (hideNotifications) { + hideNotificationsForPackages(pkgList); + } else if (unhideNotifications) { + unhideNotificationsForPackages(pkgList); } } @@ -1429,10 +1427,8 @@ public class NotificationManagerService extends SystemService { private final class SettingsObserver extends ContentObserver { private final Uri NOTIFICATION_BADGING_URI = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING); - private final Uri NOTIFICATION_BUBBLES_URI_GLOBAL + private final Uri NOTIFICATION_BUBBLES_URI = Settings.Global.getUriFor(Settings.Global.NOTIFICATION_BUBBLES); - private final Uri NOTIFICATION_BUBBLES_URI_SECURE - = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES); private final Uri NOTIFICATION_LIGHT_PULSE_URI = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); private final Uri NOTIFICATION_RATE_LIMIT_URI @@ -1450,9 +1446,7 @@ public class NotificationManagerService extends SystemService { false, this, UserHandle.USER_ALL); resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI, false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_GLOBAL, - false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI_SECURE, + resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI, false, this, UserHandle.USER_ALL); update(null); } @@ -1479,41 +1473,9 @@ public class NotificationManagerService extends SystemService { if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) { mPreferencesHelper.updateBadgingEnabled(); } - // In QPR we moved the setting to Global rather than Secure so that the setting - // applied to work profiles. Unfortunately we need to maintain both to pass CTS without - // a change to CTS outside of a normal letter release. - if (uri == null || NOTIFICATION_BUBBLES_URI_GLOBAL.equals(uri)) { - syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_GLOBAL); + if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) { mPreferencesHelper.updateBubblesEnabled(); } - if (NOTIFICATION_BUBBLES_URI_SECURE.equals(uri)) { - syncBubbleSettings(resolver, NOTIFICATION_BUBBLES_URI_SECURE); - } - } - - private void syncBubbleSettings(ContentResolver resolver, Uri settingToFollow) { - boolean followSecureSetting = settingToFollow.equals(NOTIFICATION_BUBBLES_URI_SECURE); - - int secureSettingValue = Settings.Secure.getInt(resolver, - Settings.Secure.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); - int globalSettingValue = Settings.Global.getInt(resolver, - Settings.Global.NOTIFICATION_BUBBLES, DEFAULT_ALLOW_BUBBLE ? 1 : 0); - - if (globalSettingValue == secureSettingValue) { - return; - } - - if (followSecureSetting) { - // Global => secure - Settings.Global.putInt(resolver, - Settings.Global.NOTIFICATION_BUBBLES, - secureSettingValue); - } else { - // Secure => Global - Settings.Secure.putInt(resolver, - Settings.Secure.NOTIFICATION_BADGING, - globalSettingValue); - } } } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 83bea9dd1efc..9e7b46485d4c 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -738,6 +738,25 @@ public final class OverlayManagerService extends SystemService { } @Override + public void invalidateCachesForOverlay(@Nullable String packageName, int userId) + throws RemoteException { + if (packageName == null) { + return; + } + + enforceChangeOverlayPackagesPermission("invalidateCachesForOverlay"); + userId = handleIncomingUser(userId, "invalidateCachesForOverlay"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + mImpl.removeIdmapForOverlay(packageName, userId); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public void onShellCommand(@NonNull final FileDescriptor in, @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, @NonNull final String[] args, @NonNull final ShellCallback callback, diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 934511bf88d1..019c9528f8ab 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -651,6 +651,11 @@ final class OverlayManagerServiceImpl { return mDefaultOverlays; } + void removeIdmapForOverlay(String packageName, int userId) { + final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); + removeIdmapIfPossible(oi); + } + List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName, final int userId) { final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName, diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 8b242242cbe3..a7d423784b4b 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -259,6 +259,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK // atomic install which needs to query sessions, which requires lock on mSessions. for (PackageInstallerSession session : stagedSessionsToRestore) { + if (mPm.isDeviceUpgrading()) { + session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Build fingerprint has changed"); + } mStagingManager.restoreSession(session); } // Broadcasts are not sent while we restore sessions on boot, since no processes would be diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 282fed8434ed..aac0f906feaa 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -51,7 +51,6 @@ import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; -import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -702,40 +701,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C dumpOutputStream.flush(); } - /** - * Get filtered SMS messages for financial app. - */ - @Override - public void getSmsMessagesForFinancialApp( - String callingPkg, Bundle params, IFinancialSmsCallback callback) { - int mode = PermissionChecker.checkCallingOrSelfPermission( - getContext(), - AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); - - if (mode == PermissionChecker.PERMISSION_GRANTED) { - FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext()); - financialSmsManager.getSmsMessages(new RemoteCallback((result) -> { - CursorWindow messages = null; - if (result == null) { - Slog.w(LOG_TAG, "result is null."); - } else { - messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS); - } - try { - callback.onGetSmsMessagesForFinancialApp(messages); - } catch (RemoteException e) { - // do nothing - } - }), params); - } else { - try { - callback.onGetSmsMessagesForFinancialApp(null); - } catch (RemoteException e) { - // do nothing - } - } - } - private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index eadd09cf46ee..425da374a5a8 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -28,6 +28,7 @@ import android.util.Slog; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; @@ -288,19 +289,25 @@ class RollbackStore { JSONObject dataJson = new JSONObject( IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath())); - return new Rollback( - rollbackInfoFromJson(dataJson.getJSONObject("info")), - backupDir, - Instant.parse(dataJson.getString("timestamp")), - dataJson.getInt("stagedSessionId"), - rollbackStateFromString(dataJson.getString("state")), - dataJson.getInt("apkSessionId"), - dataJson.getBoolean("restoreUserDataInProgress")); + return rollbackFromJson(dataJson, backupDir); } catch (JSONException | DateTimeParseException | ParseException e) { throw new IOException(e); } } + @VisibleForTesting + static Rollback rollbackFromJson(JSONObject dataJson, File backupDir) + throws JSONException, ParseException { + return new Rollback( + rollbackInfoFromJson(dataJson.getJSONObject("info")), + backupDir, + Instant.parse(dataJson.getString("timestamp")), + dataJson.getInt("stagedSessionId"), + rollbackStateFromString(dataJson.getString("state")), + dataJson.getInt("apkSessionId"), + dataJson.getBoolean("restoreUserDataInProgress")); + } + private static JSONObject toJson(VersionedPackage pkg) throws JSONException { JSONObject json = new JSONObject(); json.put("packageName", pkg.getPackageName()); diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 4c935643da55..5493afd1b123 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -365,10 +365,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, fout)) return; IndentingPrintWriter pw = new IndentingPrintWriter(fout, " "); - TextClassificationManager tcm = mContext.getSystemService(TextClassificationManager.class); - tcm.dump(pw); - pw.printPair("context", mContext); pw.println(); + // Create a TCM instance with the system server identity. TCM creates a ContentObserver + // to listen for settings changes. It does not pass the checkContentProviderAccess check + // if we are using the shell identity, because AMS does not track of processes spawn from + // shell. + Binder.withCleanCallingIdentity( + () -> mContext.getSystemService(TextClassificationManager.class).dump(pw)); + + pw.printPair("context", mContext); + pw.println(); synchronized (mLock) { int size = mUserStates.size(); pw.print("Number user states: "); pw.println(size); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c3ff28530b7f..b118cdfeb84d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11902,10 +11902,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { int uid = packageManager.getPackageUidAsUser(packageName, user.getIdentifier()); - - // TODO: Prevent noting the app-op - granted = PermissionChecker.checkPermission(mContext, permission, -1, - uid, packageName); + if (PermissionChecker.checkPermissionForPreflight(mContext, permission, + PermissionChecker.PID_UNKNOWN, uid, packageName) + != PermissionChecker.PERMISSION_GRANTED) { + granted = PackageManager.PERMISSION_DENIED; + } else { + granted = PackageManager.PERMISSION_GRANTED; + } } catch (NameNotFoundException e) { throw new RemoteException( "Cannot check if " + permission + "is a runtime permission", e, diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 1685b04cf2ca..8b3c85e8a7f3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -82,6 +82,7 @@ import android.os.Build; import android.os.IBinder; import android.os.PowerManagerInternal; import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseArray; @@ -103,6 +104,7 @@ import java.util.ArrayList; * Build/Install/Run: * atest MockingOomAdjusterTests */ +@Presubmit public class MockingOomAdjusterTests { private static final int MOCKAPP_PID = 12345; private static final int MOCKAPP_UID = 12345; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index 73dcb98abc8c..43f251a9281f 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -46,6 +46,7 @@ import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -140,6 +141,8 @@ public class AbstractAccessibilityServiceConnectionTest { private final List<AccessibilityWindowInfo> mA11yWindowInfosOnSecondDisplay = new ArrayList<>(); private Callable[] mFindA11yNodesFunctions; private Callable<Boolean> mPerformA11yAction; + private ArrayList<Integer> mDisplayList = new ArrayList<>(Arrays.asList( + Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID)); // To mock package-private class. @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = @@ -184,6 +187,7 @@ public class AbstractAccessibilityServiceConnectionTest { addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true, Display.DEFAULT_DISPLAY); addA11yWindowInfo(mA11yWindowInfosOnSecondDisplay, WINDOWID_ONSECONDDISPLAY, false, SECONDARY_DISPLAY_ID); + when(mMockA11yWindowManager.getDisplayListLocked()).thenReturn(mDisplayList); when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)) .thenReturn(mA11yWindowInfos); when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) @@ -285,7 +289,14 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getWindows() { - assertThat(mServiceConnection.getWindows(), is(mA11yWindowInfos)); + final AccessibilityWindowInfo.WindowListSparseArray allWindows = + mServiceConnection.getWindows(); + + assertEquals(2, allWindows.size()); + assertThat(allWindows.get(Display.DEFAULT_DISPLAY), is(mA11yWindowInfos)); + assertEquals(2, allWindows.get(Display.DEFAULT_DISPLAY).size()); + assertThat(allWindows.get(SECONDARY_DISPLAY_ID), is(mA11yWindowInfosOnSecondDisplay)); + assertEquals(1, allWindows.get(SECONDARY_DISPLAY_ID).size()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java index b7b5a4eaacfa..b5e5deb9ff59 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -67,6 +67,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -104,6 +105,9 @@ public class AccessibilityWindowManagerTest { // List of callback, mapping from displayId -> callback. private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows = new SparseArray<>(); + // List of display ID. + private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList( + Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID)); private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null); @@ -692,6 +696,15 @@ public class AccessibilityWindowManagerTest { assertTrue(windowId >= 0); } + @Test + public void getDisplayList() throws RemoteException { + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + + final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(); + assertTrue(displayList.equals(mExpectedDisplayList)); + } + private void startTrackingPerDisplay(int displayId) throws RemoteException { ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>(); // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java index 11bd29d8a163..ad3e040aca72 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java @@ -28,6 +28,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -114,6 +115,7 @@ public class ArcTerminationActionFromAvrTest { } @Test + @Ignore("b/120845532") public void testSendMessage_notSuccess() { mSendCecCommandSuccess = false; mShouldDispatchReportArcTerminated = false; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index a89198ae3708..0a1899be8c1f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -232,6 +232,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + @Ignore("b/120845532") public void handleGiveSystemAudioModeStatus_originalOff() throws Exception { HdmiCecMessage expectedMessage = HdmiCecMessageBuilder.buildReportSystemAudioMode( @@ -301,6 +302,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + @Ignore("b/120845532") public void handleSetSystemAudioMode_setOn_orignalOff() throws Exception { mMusicMute = true; HdmiCecMessage messageSet = @@ -328,6 +330,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + @Ignore("b/120845532") public void handleSystemAudioModeRequest_turnOffByTv() throws Exception { assertThat(mMusicMute).isFalse(); // Check if feature correctly turned off @@ -497,6 +500,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + @Ignore("b/120845532") public void handleRequestArcTerminate_arcIsNotOn() throws Exception { assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse(); HdmiCecMessage message = @@ -671,6 +675,7 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + @Ignore("b/120845532") public void handleReportPhysicalAddress_differentPath_addDevice() { assertThat(mInvokeDeviceEventState).isNotEqualTo(DEVICE_EVENT_ADD_DEVICE); HdmiDeviceInfo oldDevice = new HdmiDeviceInfo( diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index b8799c3f16f7..0062a1751802 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -99,6 +99,7 @@ public class HdmiCecLocalDevicePlaybackTest { } @Test + @Ignore("b/120845532") public void handleSetSystemAudioModeOn_audioSystemBroadcast() { mHdmiControlService.setSystemAudioActivated(false); assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse(); @@ -110,6 +111,7 @@ public class HdmiCecLocalDevicePlaybackTest { } @Test + @Ignore("b/120845532") public void handleSetSystemAudioModeOff_audioSystemToPlayback() { mHdmiCecLocalDevicePlayback.mService.setSystemAudioActivated(true); assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isTrue(); @@ -123,6 +125,7 @@ public class HdmiCecLocalDevicePlaybackTest { } @Test + @Ignore("b/120845532") public void handleSystemAudioModeStatusOn_DirectltToLocalDeviceFromAudioSystem() { mHdmiControlService.setSystemAudioActivated(false); assertThat(mHdmiCecLocalDevicePlayback.mService.isSystemAudioActivated()).isFalse(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java new file mode 100644 index 000000000000..c6cf9b116a1d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.hdmi; + +import static android.os.SystemClock.sleep; +import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.Assert.assertEquals; + +import android.hardware.hdmi.HdmiControlManager; +import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; +import android.os.Looper; +import android.os.SystemProperties; +import android.os.test.TestLooper; +import android.util.Slog; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import java.util.ArrayList; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link HdmiControlServiceBinderAPITest} class. + */ +@SmallTest +@RunWith(JUnit4.class) +public class HdmiControlServiceBinderAPITest { + + private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDevice { + + private boolean mCanGoToStandby; + private boolean mIsStandby; + private boolean mIsDisabled; + + protected HdmiCecLocalDeviceMyDevice(HdmiControlService service, int deviceType) { + super(service, deviceType); + } + + @Override + protected void onAddressAllocated(int logicalAddress, int reason) { + } + + @Override + protected int getPreferredAddress() { + return 0; + } + + @Override + protected void setPreferredAddress(int addr) { + } + + @Override + protected boolean canGoToStandby() { + return mCanGoToStandby; + } + + @Override + protected void disableDevice( + boolean initiatedByCec, final PendingActionClearedCallback originalCallback) { + mIsDisabled = true; + originalCallback.onCleared(this); + } + + @Override + protected void onStandby(boolean initiatedByCec, int standbyAction) { + mIsStandby = true; + } + + protected boolean isStandby() { + return mIsStandby; + } + + protected boolean isDisabled() { + return mIsDisabled; + } + + protected void setCanGoToStandby(boolean canGoToStandby) { + mCanGoToStandby = canGoToStandby; + } + } + + private static final String TAG = "HdmiControlServiceBinderAPITest"; + private HdmiControlService mHdmiControlService; + private HdmiCecController mHdmiCecController; + private HdmiCecLocalDevicePlayback mPlaybackDevice; + private FakeNativeWrapper mNativeWrapper; + private Looper mMyLooper; + private TestLooper mTestLooper = new TestLooper(); + private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); + private HdmiPortInfo[] mHdmiPortInfo; + private int mResult; + private int mPowerStatus; + + @Before + public void SetUp() { + mHdmiControlService = + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { + @Override + void sendCecCommand(HdmiCecMessage command) { + switch (command.getOpcode()) { + case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS: + HdmiCecMessage message = + HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, + Constants.ADDR_PLAYBACK_1, + HdmiControlManager.POWER_STATUS_ON); + handleCecCommand(message); + break; + default: + return; + } + } + + @Override + boolean isPowerStandby() { + return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; + } + }; + mMyLooper = mTestLooper.getLooper(); + + mPlaybackDevice = new HdmiCecLocalDevicePlayback(mHdmiControlService) { + @Override + void setIsActiveSource(boolean on) { + mIsActiveSource = on; + } + + @Override + protected void wakeUpIfActiveSource() {} + + @Override + protected void setPreferredAddress(int addr) {} + + @Override + protected int getPreferredAddress() { + return Constants.ADDR_PLAYBACK_1; + } + }; + mPlaybackDevice.init(); + + mHdmiControlService.setIoLooper(mMyLooper); + + mNativeWrapper = new FakeNativeWrapper(); + mHdmiCecController = + HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper); + mHdmiControlService.setCecController(mHdmiCecController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); + mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); + + mLocalDevices.add(mPlaybackDevice); + mHdmiPortInfo = new HdmiPortInfo[1]; + mHdmiPortInfo[0] = + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false); + mNativeWrapper.setPortInfo(mHdmiPortInfo); + mHdmiControlService.initPortInfo(); + mResult = -1; + mPowerStatus = HdmiControlManager.POWER_STATUS_ON; + + mTestLooper.dispatchAll(); + } + + @Test + public void oneTouchPlay_addressNotAllocated() { + assertThat(mHdmiControlService.isAddressAllocated()).isFalse(); + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + mResult = result; + } + }); + assertEquals(mResult, -1); + assertThat(mPlaybackDevice.mIsActiveSource).isFalse(); + + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + assertThat(mHdmiControlService.isAddressAllocated()).isTrue(); + assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS); + assertThat(mPlaybackDevice.mIsActiveSource).isTrue(); + } + + @Test + public void oneTouchPlay_addressAllocated() { + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + assertThat(mHdmiControlService.isAddressAllocated()).isTrue(); + mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + mResult = result; + } + }); + assertEquals(mResult, HdmiControlManager.RESULT_SUCCESS); + assertThat(mPlaybackDevice.mIsActiveSource).isTrue(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java index 440a49ab81fc..6dcff3574faf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java @@ -221,6 +221,7 @@ public class SystemAudioInitiationActionFromAvrTest { } @Test + @Ignore("b/120845532") public void testTvSupport() { resetTestVariables(); mShouldDispatchActiveSource = true; diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java new file mode 100644 index 000000000000..4321c21f68b2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.integrity.model; + +import static com.android.server.testutils.TestUtils.assertExpectException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class RuleTest { + + private static final Rule.Effect DENY_EFFECT = Rule.Effect.DENY; + private static final Rule.Formula SIMPLE_FORMULA = + new Rule.AtomicFormula(Rule.Key.PACKAGE_NAME, Rule.Operator.EQ, "com.test.app"); + + @Test + public void testEmptyRule() { + Rule emptyRule = Rule.EMPTY; + + assertNull(emptyRule.getFormula()); + assertNull(emptyRule.getEffect()); + } + + @Test + public void testValidRule() { + Rule validRule = new Rule(SIMPLE_FORMULA, DENY_EFFECT); + + assertEquals(SIMPLE_FORMULA, validRule.getFormula()); + assertEquals(DENY_EFFECT, validRule.getEffect()); + } + + @Test + public void testInvalidRule_invalidEffect() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(SIMPLE_FORMULA, null)); + } + + @Test + public void testInvalidRule_invalidFormula() { + assertExpectException( + NullPointerException.class, + /* expectedExceptionMessageRegex */ null, + () -> new Rule(null, DENY_EFFECT)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 7cece1f5cecc..f9ac02271a27 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -32,8 +32,11 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DeviceStateCache; import android.app.trust.TrustManager; import android.content.ComponentName; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.hardware.authsecret.V1_0.IAuthSecret; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; @@ -95,6 +98,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { RecoverableKeyStoreManager mRecoverableKeyStoreManager; UserManagerInternal mUserManagerInternal; DeviceStateCache mDeviceStateCache; + FingerprintManager mFingerprintManager; + FaceManager mFaceManager; + PackageManager mPackageManager; protected boolean mHasSecureLockScreen; @Override @@ -114,6 +120,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mRecoverableKeyStoreManager = mock(RecoverableKeyStoreManager.class); mUserManagerInternal = mock(UserManagerInternal.class); mDeviceStateCache = mock(DeviceStateCache.class); + mFingerprintManager = mock(FingerprintManager.class); + mFaceManager = mock(FaceManager.class); + mPackageManager = mock(PackageManager.class); LocalServices.removeServiceForTest(LockSettingsInternal.class); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); @@ -123,7 +132,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class), - mock(KeyguardManager.class)); + mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; @@ -181,6 +190,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { new ComponentName("com.dummy.package", ".FakeDeviceOwner")); when(mUserManagerInternal.isDeviceManaged()).thenReturn(true); when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true); + mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID); + mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID); mLocalService = LocalServices.getService(LockSettingsInternal.class); } @@ -233,6 +244,18 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { return sm; } + private void mockBiometricsHardwareFingerprintsAndTemplates(int userId) { + // Hardware must be detected and fingerprints must be enrolled + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + when(mFingerprintManager.hasEnrolledFingerprints(userId)).thenReturn(true); + + // Hardware must be detected and templates must be enrolled + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + when(mFaceManager.hasEnrolledTemplates(userId)).thenReturn(true); + } + @Override protected void tearDown() throws Exception { super.tearDown(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 65d6f45b5c6c..fcd98e0742ea 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -23,7 +23,6 @@ import android.app.admin.DeviceStateCache; import android.content.Context; import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.Handler; -import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.UserManagerInternal; @@ -32,6 +31,7 @@ import android.security.KeyStore; import android.security.keystore.KeyPermanentlyInvalidatedException; import com.android.internal.widget.LockPatternUtils; +import com.android.server.ServiceThread; import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager; import java.io.FileNotFoundException; @@ -70,8 +70,8 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public Handler getHandler() { - return new Handler(Looper.getMainLooper()); + public Handler getHandler(ServiceThread handlerThread) { + return new Handler(handlerThread.getLooper()); } @Override diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 7354ad4b9ac3..5818133aa2a4 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -330,6 +330,27 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, MANAGED_PROFILE_USER_ID); } + public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException { + final String oldCredential = "oldPassword"; + + initializeStorageWithCredential( + PRIMARY_USER_ID, + oldCredential, + CREDENTIAL_TYPE_PATTERN, + PASSWORD_QUALITY_SOMETHING); + mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); + + mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, oldCredential.getBytes(), + PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false); + + // Verify fingerprint is removed + verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any()); + verify(mFaceManager).remove(any(), eq(PRIMARY_USER_ID), any()); + + verify(mFingerprintManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any()); + verify(mFaceManager).remove(any(), eq(MANAGED_PROFILE_USER_ID), any()); + } + public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials() throws Exception { final String parentPassword = "parentPassword"; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java index 8e0d7be5f44f..2a169b775ca3 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java @@ -24,8 +24,11 @@ import android.app.KeyguardManager; import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.sqlite.SQLiteDatabase; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.FileUtils; import android.os.SystemClock; import android.os.UserManager; @@ -86,7 +89,9 @@ public class LockSettingsStorageTests extends AndroidTestCase { MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager, mock(NotificationManager.class), mock(DevicePolicyManager.class), - mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class)); + mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class), + mock(FingerprintManager.class), mock(FaceManager.class), + mock(PackageManager.class)); mStorage = new LockSettingsStorageTestable(context, new File(getContext().getFilesDir(), "locksettings")); mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java index b33253264317..2b9a05c3ef63 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java @@ -23,6 +23,8 @@ import android.app.trust.TrustManager; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.PackageManager; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.UserManager; import android.os.storage.StorageManager; @@ -34,11 +36,15 @@ public class MockLockSettingsContext extends ContextWrapper { private StorageManager mStorageManager; private TrustManager mTrustManager; private KeyguardManager mKeyguardManager; + private FingerprintManager mFingerprintManager; + private FaceManager mFaceManager; + private PackageManager mPackageManager; public MockLockSettingsContext(Context base, UserManager userManager, NotificationManager notificationManager, DevicePolicyManager devicePolicyManager, StorageManager storageManager, TrustManager trustManager, - KeyguardManager keyguardManager) { + KeyguardManager keyguardManager, FingerprintManager fingerprintManager, + FaceManager faceManager, PackageManager packageManager) { super(base); mUserManager = userManager; mNotificationManager = notificationManager; @@ -46,6 +52,9 @@ public class MockLockSettingsContext extends ContextWrapper { mStorageManager = storageManager; mTrustManager = trustManager; mKeyguardManager = keyguardManager; + mFingerprintManager = fingerprintManager; + mFaceManager = faceManager; + mPackageManager = packageManager; } @Override @@ -62,12 +71,21 @@ public class MockLockSettingsContext extends ContextWrapper { return mTrustManager; } else if (KEYGUARD_SERVICE.equals(name)) { return mKeyguardManager; + } else if (FINGERPRINT_SERVICE.equals(name)) { + return mFingerprintManager; + } else if (FACE_SERVICE.equals(name)) { + return mFaceManager; } else { throw new RuntimeException("System service not mocked: " + name); } } @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + + @Override public void enforceCallingOrSelfPermission(String permission, String message) { // Skip permission checks for unit tests. } diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java index 806c71a7a9b8..6d5b994a63bb 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java @@ -132,6 +132,7 @@ public class UserManagerServiceUserInfoTest { user.profileBadge = 2; user.partial = true; user.guestToRemove = true; + user.preCreated = true; return user; } @@ -147,5 +148,6 @@ public class UserManagerServiceUserInfoTest { assertEquals("profile badge not preseved", one.profileBadge, two.profileBadge); assertEquals("partial not preseved", one.partial, two.partial); assertEquals("guestToRemove not preseved", one.guestToRemove, two.guestToRemove); + assertEquals("preCreated not preseved", one.preCreated, two.preCreated); } } diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java new file mode 100644 index 000000000000..ee3b15a97f26 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.rollback; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.pm.VersionedPackage; +import android.content.rollback.PackageRollbackInfo; +import android.util.IntArray; +import android.util.SparseLongArray; + +import com.google.common.truth.Correspondence; + +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@RunWith(JUnit4.class) +public class RollbackStoreTest { + + private static final int ID = 123; + + private static final Correspondence<VersionedPackage, VersionedPackage> VER_PKG_CORR = + new Correspondence<VersionedPackage, VersionedPackage>() { + @Override + public boolean compare(VersionedPackage a, VersionedPackage b) { + if (a == null || b == null) { + return a == b; + } + return a.getLongVersionCode() == b.getLongVersionCode() + && Objects.equals(a.getPackageName(), b.getPackageName()); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + private static final Correspondence<PackageRollbackInfo.RestoreInfo, + PackageRollbackInfo.RestoreInfo> + RESTORE_INFO_CORR = + new Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo>() { + @Override + public boolean compare(PackageRollbackInfo.RestoreInfo a, + PackageRollbackInfo.RestoreInfo b) { + if (a == null || b == null) { + return a == b; + } + return a.userId == b.userId + && a.appId == b.appId + && Objects.equals(a.seInfo, b.seInfo); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + private static final String JSON_ROLLBACK = "{'info':{'rollbackId':123,'packages':" + + "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55}," + + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':" + + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'}," + + "{'userId':-895,'appId':1,'seInfo':'pingu'}],'isApex':false,'installedUsers':" + + "[498468432,1111,98464],'ceSnapshotInodes':[{'userId':1,'ceSnapshotInode':-6}," + + "{'userId':2222,'ceSnapshotInode':81641654445},{'userId':546546," + + "'ceSnapshotInode':345689375}]},{'versionRolledBackFrom':{'packageName':'chips'," + + "'longVersionCode':28},'versionRolledBackTo':{'packageName':'com.chips.test'," + + "'longVersionCode':48},'pendingBackups':[5],'pendingRestores':[{'userId':18," + + "'appId':-12,'seInfo':''}],'isApex':false,'installedUsers':[55,79]," + + "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello'," + + "'longVersionCode':23},{'packageName':'something','longVersionCode':999}]," + + "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z'," + + "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1," + + "'restoreUserDataInProgress':true}"; + + @Rule + public TemporaryFolder mFolder = new TemporaryFolder(); + + private File mRollbackDir; + + private RollbackStore mRollbackStore; + + @Before + public void setUp() throws Exception { + mRollbackStore = new RollbackStore(mFolder.getRoot()); + mRollbackDir = mFolder.newFolder(ID + ""); + mFolder.newFile("rollback.json"); + } + + @Test + public void createNonStaged() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isFalse(); + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void createStaged() { + Rollback rollback = mRollbackStore.createStagedRollback(ID, 897); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isTrue(); + assertThat(rollback.getStagedSessionId()).isEqualTo(897); + + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void saveAndLoadRollback() { + Rollback origRb = mRollbackStore.createNonStagedRollback(ID); + + origRb.setRestoreUserDataInProgress(true); + origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); + origRb.info.getCausePackages().add(new VersionedPackage("com.pack.age", 99)); + origRb.info.setCommittedSessionId(123456); + + PackageRollbackInfo pkgInfo1 = + new PackageRollbackInfo(new VersionedPackage("com.made.up", 18), + new VersionedPackage("com.something.else", 5), new IntArray(), + new ArrayList<>(), false, new IntArray(), new SparseLongArray()); + pkgInfo1.getPendingBackups().add(8); + pkgInfo1.getPendingBackups().add(888); + pkgInfo1.getPendingBackups().add(88885); + pkgInfo1.getCeSnapshotInodes().put(12, 424); + pkgInfo1.getCeSnapshotInodes().put(222772, 10000000000L); + pkgInfo1.getCeSnapshotInodes().put(10, -67); + + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(4980, 3442322, "seInfo")); + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(-89, 15, "otherSeInfo")); + + pkgInfo1.getSnapshottedUsers().add(11); + pkgInfo1.getSnapshottedUsers().add(1); + pkgInfo1.getSnapshottedUsers().add(0); + + PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo( + new VersionedPackage("another.package", 2), + new VersionedPackage("com.test.ing", 48888), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo2.getPendingBackups().add(57); + + pkgInfo2.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(180, -120, "")); + + origRb.info.getPackages().add(pkgInfo1); + origRb.info.getPackages().add(pkgInfo2); + + RollbackStore.saveRollback(origRb); + + List<Rollback> loadedRollbacks = mRollbackStore.loadRollbacks(); + assertThat(loadedRollbacks).hasSize(1); + Rollback loadedRb = loadedRollbacks.get(0); + + assertRollbacksAreEquivalent(loadedRb, origRb); + } + + @Test + public void loadFromJson() throws Exception { + Rollback expectedRb = mRollbackStore.createNonStagedRollback(ID); + + expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z")); + expectedRb.setRestoreUserDataInProgress(true); + expectedRb.info.getCausePackages().add(new VersionedPackage("hello", 23)); + expectedRb.info.getCausePackages().add(new VersionedPackage("something", 999)); + expectedRb.info.setCommittedSessionId(45654465); + + PackageRollbackInfo pkgInfo1 = new PackageRollbackInfo(new VersionedPackage("blah", 55), + new VersionedPackage("blah1", 50), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo1.getPendingBackups().add(59); + pkgInfo1.getPendingBackups().add(1245); + pkgInfo1.getPendingBackups().add(124544); + pkgInfo1.getCeSnapshotInodes().put(546546, 345689375); + pkgInfo1.getCeSnapshotInodes().put(2222, 81641654445L); + pkgInfo1.getCeSnapshotInodes().put(1, -6); + + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(498, 32322, "wombles")); + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(-895, 1, "pingu")); + + pkgInfo1.getSnapshottedUsers().add(498468432); + pkgInfo1.getSnapshottedUsers().add(1111); + pkgInfo1.getSnapshottedUsers().add(98464); + + PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo(new VersionedPackage("chips", 28), + new VersionedPackage("com.chips.test", 48), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo2.getPendingBackups().add(5); + + pkgInfo2.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(18, -12, "")); + + pkgInfo2.getSnapshottedUsers().add(55); + pkgInfo2.getSnapshottedUsers().add(79); + + expectedRb.info.getPackages().add(pkgInfo1); + expectedRb.info.getPackages().add(pkgInfo2); + + Rollback parsedRb = RollbackStore.rollbackFromJson( + new JSONObject(JSON_ROLLBACK), expectedRb.getBackupDir()); + + assertRollbacksAreEquivalent(parsedRb, expectedRb); + } + + @Test + public void saveAndDelete() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + RollbackStore.saveRollback(rollback); + + File expectedFile = new File(mRollbackDir.getAbsolutePath() + "/rollback.json"); + + assertThat(expectedFile.exists()).isTrue(); + + RollbackStore.deleteRollback(rollback); + + assertThat(expectedFile.exists()).isFalse(); + } + + private void assertRollbacksAreEquivalent(Rollback b, Rollback a) { + assertThat(b.info.getRollbackId()).isEqualTo(ID); + + assertThat(b.getBackupDir()).isEqualTo(a.getBackupDir()); + + assertThat(b.isRestoreUserDataInProgress()) + .isEqualTo(a.isRestoreUserDataInProgress()); + + assertThat(b.getTimestamp()).isEqualTo(a.getTimestamp()); + + assertThat(b.isEnabling()).isEqualTo(a.isEnabling()); + assertThat(b.isAvailable()).isEqualTo(a.isAvailable()); + assertThat(b.isCommitted()).isEqualTo(a.isCommitted()); + + assertThat(b.isStaged()).isEqualTo(a.isStaged()); + + assertThat(b.getApexPackageNames()) + .containsExactlyElementsIn(a.getApexPackageNames()); + + assertThat(b.getStagedSessionId()).isEqualTo(a.getStagedSessionId()); + + assertThat(b.info.getCommittedSessionId()).isEqualTo(a.info.getCommittedSessionId()); + + assertThat(b.info.getCausePackages()).comparingElementsUsing(VER_PKG_CORR) + .containsExactlyElementsIn(a.info.getCausePackages()); + + assertThat(b.info.getPackages()).hasSize(a.info.getPackages().size()); + + for (int i = 0; i < b.info.getPackages().size(); i++) { + assertPackageRollbacksAreEquivalent( + b.info.getPackages().get(i), a.info.getPackages().get(i)); + } + } + + private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) { + assertThat(b.getPackageName()).isEqualTo(a.getPackageName()); + + assertThat(b.getVersionRolledBackFrom().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackFrom().getLongVersionCode()); + assertThat(b.getVersionRolledBackFrom().getPackageName()) + .isEqualTo(a.getVersionRolledBackFrom().getPackageName()); + + assertThat(b.getVersionRolledBackTo().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackTo().getLongVersionCode()); + assertThat(b.getVersionRolledBackTo().getPackageName()) + .isEqualTo(a.getVersionRolledBackTo().getPackageName()); + + assertThat(b.getPendingBackups().toArray()).isEqualTo(a.getPendingBackups().toArray()); + + assertThat(b.getPendingRestores()).comparingElementsUsing(RESTORE_INFO_CORR) + .containsExactlyElementsIn(a.getPendingRestores()); + + assertThat(b.isApex()).isEqualTo(a.isApex()); + + assertThat(b.getSnapshottedUsers().toArray()).isEqualTo(a.getSnapshottedUsers().toArray()); + + assertThat(b.getCeSnapshotInodes().toString()) + .isEqualTo(a.getCeSnapshotInodes().toString()); + } + +} 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 2de8d0579ec4..e80c6291b42a 100644..100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3864,7 +3864,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.simulatePackageDistractionBroadcast( PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"}); ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); - verify(mListeners, times(2)).notifyHiddenLocked(captorHide.capture()); + + // should be called only once. + verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); assertEquals(2, captorHide.getValue().size()); assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName()); assertEquals("b", captorHide.getValue().get(1).sbn.getPackageName()); @@ -3873,7 +3875,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.simulatePackageDistractionBroadcast( PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"}); ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); - verify(mListeners, times(2)).notifyUnhiddenLocked(captorUnhide.capture()); + + // should be called only once. + verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); assertEquals(2, captorUnhide.getValue().size()); assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName()); assertEquals("b", captorUnhide.getValue().get(1).sbn.getPackageName()); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 59d07357ff56..34eb3f16bf2a 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -97,6 +97,8 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Arrays; @@ -159,7 +161,7 @@ public class UsageStatsService extends SystemService implements int mUsageSource; /** Manages the standby state of apps. */ - AppStandbyController mAppStandby; + AppStandbyInternal mAppStandby; /** Manages app time limit observers */ AppTimeLimitController mAppTimeLimit; @@ -208,7 +210,9 @@ public class UsageStatsService extends SystemService implements mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mHandler = new H(BackgroundThread.get().getLooper()); - mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper()); + mAppStandby = AppStandbyInternal.newAppStandbyController( + UsageStatsService.class.getClassLoader(), getContext(), + BackgroundThread.get().getLooper()); mAppTimeLimit = new AppTimeLimitController( new AppTimeLimitController.TimeLimitCallbackListener() { @@ -1010,7 +1014,7 @@ public class UsageStatsService extends SystemService implements pw.println("Flushed stats to disk"); return; } else if ("is-app-standby-enabled".equals(arg)) { - pw.println(mAppStandby.mAppIdleEnabled); + pw.println(mAppStandby.isAppIdleEnabled()); return; } else if ("apptimelimit".equals(arg)) { if (i + 1 >= args.length) { diff --git a/telephony/java/android/telephony/CellBroadcastService.java b/telephony/java/android/telephony/CellBroadcastService.java new file mode 100644 index 000000000000..d5e447e6c73d --- /dev/null +++ b/telephony/java/android/telephony/CellBroadcastService.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.CallSuper; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * A service which exposes the cell broadcast handling module to the system. + * <p> + * To extend this class, you must declare the service in your manifest file to require the + * {@link android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE} permission and include an intent + * filter with the {@link #CELL_BROADCAST_SERVICE_INTERFACE}. + * Implementations of this service should run in the phone process and with its UID. + * <p> + * For example: + * <pre>{@code + * <manifest xmlns:android="http://schemas.android.com/apk/res/android" + * android:sharedUserId="android.uid.phone"> + * <service android:name=".MyCellBroadcastService" + * android:label="@string/service_name" + * android:process="com.android.phone" + * android:exported="true" + * android:permission="android.permission.BIND_CELL_BROADCAST_SERVICE"> + * <intent-filter> + * <action android:name="android.telephony.CellBroadcastService" /> + * </intent-filter> + * </service> + * </manifest> + * }</pre> + * @hide + */ +@SystemApi +public abstract class CellBroadcastService extends Service { + + public static final String CELL_BROADCAST_SERVICE_INTERFACE = + "android.telephony.CellBroadcastService"; + + private final ICellBroadcastService.Stub mStubWrapper; + + public CellBroadcastService() { + mStubWrapper = new ICellBroadcastServiceWrapper(); + } + + /** + * Handle a GSM cell broadcast SMS message forwarded from the system. + * @param slotIndex the index of the slot which received the message + * @param message the SMS PDU + */ + public abstract void onGsmCellBroadcastSms(int slotIndex, byte[] message); + + /** + * Handle a CDMA cell broadcast SMS message forwarded from the system. + * @param slotIndex the index of the slot which received the message + * @param message the SMS PDU + */ + public abstract void onCdmaCellBroadcastSms(int slotIndex, byte[] message); + + /** + * If overriding this method, call through to the super method for any unknown actions. + * {@inheritDoc} + */ + @Override + @CallSuper + public IBinder onBind(Intent intent) { + return mStubWrapper; + } + + /** + * A wrapper around ICellBroadcastService that forwards calls to implementations of + * {@link CellBroadcastService}. + * @hide + */ + public class ICellBroadcastServiceWrapper extends ICellBroadcastService.Stub { + /** + * Handle a GSM cell broadcast SMS. + * @param slotIndex the index of the slot which received the broadcast + * @param message the SMS message PDU + */ + @Override + public void handleGsmCellBroadcastSms(int slotIndex, byte[] message) { + CellBroadcastService.this.onGsmCellBroadcastSms(slotIndex, message); + } + + /** + * Handle a CDMA cell broadcast SMS. + * @param slotIndex the index of the slot which received the broadcast + * @param message the SMS message PDU + */ + @Override + public void handleCdmaCellBroadcastSms(int slotIndex, byte[] message) { + CellBroadcastService.this.onCdmaCellBroadcastSms(slotIndex, message); + } + } +} diff --git a/telephony/java/android/telephony/ICellBroadcastService.aidl b/telephony/java/android/telephony/ICellBroadcastService.aidl new file mode 100644 index 000000000000..eff64a2e35ba --- /dev/null +++ b/telephony/java/android/telephony/ICellBroadcastService.aidl @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +/** + * Service bound to by the system to allow custom handling of cell broadcast messages. + * <p> + * @see android.telephony.CellBroadcastService + * @hide + */ +interface ICellBroadcastService { + + /** @see android.telephony.CellBroadcastService#onGsmCellBroadcastSms */ + oneway void handleGsmCellBroadcastSms(int slotId, in byte[] message); + + /** @see android.telephony.CellBroadcastService#onCdmaCellBroadcastSms */ + oneway void handleCdmaCellBroadcastSms(int slotId, in byte[] message); +} diff --git a/telephony/java/android/telephony/IFinancialSmsCallback.aidl b/telephony/java/android/telephony/IFinancialSmsCallback.aidl deleted file mode 100644 index aa88615c15cf..000000000000 --- a/telephony/java/android/telephony/IFinancialSmsCallback.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/* -** Copyright 2019, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ -package android.telephony; - -import android.app.PendingIntent; -import android.database.CursorWindow; -import android.net.Uri; -import android.os.Bundle; -import com.android.internal.telephony.SmsRawData; - -/** Interface for returning back the financial sms messages asynchrously. - * @hide - */ -interface IFinancialSmsCallback { - /** - * Return sms messages back to calling financial app. - * - * @param messages the sms messages returned for cinancial app. - */ - oneway void onGetSmsMessagesForFinancialApp(in CursorWindow messages); -} diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index c2028f900508..1801caeb0660 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -878,6 +878,7 @@ public class PhoneStateListener { * @hide */ @SystemApi + @TestApi public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) { // default implementation empty } @@ -889,6 +890,7 @@ public class PhoneStateListener { * @hide */ @SystemApi + @TestApi public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) { // default implementation empty } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 71fcf23cb6ee..f4330fa0b725 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -33,6 +33,7 @@ import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; import android.os.Binder; +import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.RemoteException; @@ -2080,7 +2081,9 @@ public final class SmsManager { } } - /** callback for providing asynchronous sms messages for financial app. */ + /** + * callback for providing asynchronous sms messages for financial app. + */ public abstract static class FinancialSmsCallback { /** * Callback to send sms messages back to financial app asynchronously. @@ -2106,24 +2109,14 @@ public final class SmsManager { * @param params the parameters to filter SMS messages returned. * @param executor the executor on which callback will be invoked. * @param callback a callback to receive CursorWindow with SMS messages. + * */ @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp( Bundle params, @NonNull @CallbackExecutor Executor executor, @NonNull FinancialSmsCallback callback) { - try { - ISms iccSms = getISmsServiceOrThrow(); - iccSms.getSmsMessagesForFinancialApp( - getSubscriptionId(), ActivityThread.currentPackageName(), params, - new IFinancialSmsCallback.Stub() { - public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) { - Binder.withCleanCallingIdentity(() -> executor.execute( - () -> callback.onFinancialSmsMessages(msgs))); - }}); - } catch (RemoteException ex) { - ex.rethrowFromSystemServer(); - } + // This API is not functional and thus removed to avoid future confusion. } /** diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 7441c26a8061..f3a335d93a6c 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import com.android.internal.telephony.SmsRawData; /** @@ -570,17 +569,6 @@ interface ISms { int subId, String callingPkg, String prefixes, in PendingIntent intent); /** - * Get sms inbox messages for the calling financial app. - * - * @param subId the SIM id. - * @param callingPkg the package name of the calling app. - * @param params parameters to filter the sms messages. - * @param callback the callback interface to deliver the result. - */ - void getSmsMessagesForFinancialApp( - int subId, String callingPkg, in Bundle params, in IFinancialSmsCallback callback); - - /** * Check if the destination is a possible premium short code. * * @param destAddress the destination address to test for possible short code diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java index aa1f94f2355a..2096325b09f2 100644 --- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java +++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.net.Uri; import android.os.Bundle; -import android.telephony.IFinancialSmsCallback; import java.util.List; @@ -198,12 +197,6 @@ public class ISmsImplBase extends ISms.Stub { } @Override - public void getSmsMessagesForFinancialApp( - int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) { - throw new UnsupportedOperationException(); - } - - @Override public int checkSmsShortCodeDestination( int subid, String callingApk, String destAddress, String countryIso) { throw new UnsupportedOperationException(); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java index 6eea118787a7..c65c45fa015b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java @@ -461,7 +461,11 @@ public class GsmSmsCbMessage { } } - static final class GeoFencingTriggerMessage { + /** + * Part of a GSM SMS cell broadcast message which may trigger geo-fencing logic. + * @hide + */ + public static final class GeoFencingTriggerMessage { /** * Indicate the list of active alerts share their warning area coordinates which means the * broadcast area is the union of the broadcast areas of the active alerts in this list. @@ -476,6 +480,11 @@ public class GsmSmsCbMessage { this.cbIdentifiers = cbIdentifiers; } + /** + * Whether the trigger message indicates that the broadcast areas are shared between all + * active alerts. + * @return true if broadcast areas are to be shared + */ boolean shouldShareBroadcastArea() { return type == TYPE_ACTIVE_ALERT_SHARE_WAC; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java index 6bbff4b91ee7..cbe521182667 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java @@ -74,22 +74,22 @@ public class SmsCbHeader { /** * Length of SMS-CB header */ - static final int PDU_HEADER_LENGTH = 6; + public static final int PDU_HEADER_LENGTH = 6; /** * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1 */ - static final int FORMAT_GSM = 1; + public static final int FORMAT_GSM = 1; /** * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2 */ - static final int FORMAT_UMTS = 2; + public static final int FORMAT_UMTS = 2; /** - * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3 + * ETWS pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3 */ - static final int FORMAT_ETWS_PRIMARY = 3; + public static final int FORMAT_ETWS_PRIMARY = 3; /** * Message type value as defined in 3gpp TS 25.324, section 11.1. @@ -230,43 +230,43 @@ public class SmsCbHeader { } @UnsupportedAppUsage - int getGeographicalScope() { + public int getGeographicalScope() { return mGeographicalScope; } @UnsupportedAppUsage - int getSerialNumber() { + public int getSerialNumber() { return mSerialNumber; } @UnsupportedAppUsage - int getServiceCategory() { + public int getServiceCategory() { return mMessageIdentifier; } - int getDataCodingScheme() { + public int getDataCodingScheme() { return mDataCodingScheme; } - DataCodingScheme getDataCodingSchemeStructedData() { + public DataCodingScheme getDataCodingSchemeStructedData() { return mDataCodingSchemeStructedData; } @UnsupportedAppUsage - int getPageIndex() { + public int getPageIndex() { return mPageIndex; } @UnsupportedAppUsage - int getNumberOfPages() { + public int getNumberOfPages() { return mNrOfPages; } - SmsCbEtwsInfo getEtwsInfo() { + public SmsCbEtwsInfo getEtwsInfo() { return mEtwsInfo; } - SmsCbCmasInfo getCmasInfo() { + public SmsCbCmasInfo getCmasInfo() { return mCmasInfo; } @@ -274,7 +274,7 @@ public class SmsCbHeader { * Return whether this broadcast is an emergency (PWS) message type. * @return true if this message is emergency type; false otherwise */ - boolean isEmergencyMessage() { + public boolean isEmergencyMessage() { return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER; } @@ -292,7 +292,7 @@ public class SmsCbHeader { * Return whether this broadcast is an ETWS primary notification. * @return true if this message is an ETWS primary notification; false otherwise */ - boolean isEtwsPrimaryNotification() { + public boolean isEtwsPrimaryNotification() { return mFormat == FORMAT_ETWS_PRIMARY; } @@ -300,7 +300,7 @@ public class SmsCbHeader { * Return whether this broadcast is in UMTS format. * @return true if this message is in UMTS format; false otherwise */ - boolean isUmtsFormat() { + public boolean isUmtsFormat() { return mFormat == FORMAT_UMTS; } diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh index 614cbb7c9eb6..01522735ec3c 100755 --- a/tests/Codegen/runTest.sh +++ b/tests/Codegen/runTest.sh @@ -13,6 +13,7 @@ else header_and_eval m -j16 codegen_cli && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \ + header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java && \ cd $ANDROID_BUILD_TOP && header_and_eval mmma -j16 frameworks/base/tests/Codegen && \ header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \ diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java new file mode 100644 index 000000000000..2d4125783990 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.codegentest; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseArray; +import android.util.SparseIntArray; + +import com.android.internal.util.AnnotationValidations; +import com.android.internal.util.DataClass; + +import java.util.List; +import java.util.Map; + +/** + * Additional test for various parcelling corner-cases. + */ +@DataClass( + genBuilder = true, + genAidl = false, + genToString = true) +public class ParcelAllTheThingsDataClass implements Parcelable { + + @NonNull String[] mStringArray = null; + @NonNull int[] mIntArray = null; + @NonNull List<String> mStringList = null; + + @NonNull Map<String, SampleWithCustomBuilder> mMap = null; + @NonNull Map<String, String> mStringMap = null; + + @NonNull SparseArray<SampleWithCustomBuilder> mSparseArray = null; + @NonNull SparseIntArray mSparseIntArray = null; + + + + // Code below generated by codegen v1.0.4. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java + + + @DataClass.Generated.Member + /* package-private */ ParcelAllTheThingsDataClass( + @NonNull String[] stringArray, + @NonNull int[] intArray, + @NonNull List<String> stringList, + @NonNull Map<String,SampleWithCustomBuilder> map, + @NonNull Map<String,String> stringMap, + @NonNull SparseArray<SampleWithCustomBuilder> sparseArray, + @NonNull SparseIntArray sparseIntArray) { + this.mStringArray = stringArray; + AnnotationValidations.validate( + NonNull.class, null, mStringArray); + this.mIntArray = intArray; + AnnotationValidations.validate( + NonNull.class, null, mIntArray); + this.mStringList = stringList; + AnnotationValidations.validate( + NonNull.class, null, mStringList); + this.mMap = map; + AnnotationValidations.validate( + NonNull.class, null, mMap); + this.mStringMap = stringMap; + AnnotationValidations.validate( + NonNull.class, null, mStringMap); + this.mSparseArray = sparseArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseArray); + this.mSparseIntArray = sparseIntArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseIntArray); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull String[] getStringArray() { + return mStringArray; + } + + @DataClass.Generated.Member + public @NonNull int[] getIntArray() { + return mIntArray; + } + + @DataClass.Generated.Member + public @NonNull List<String> getStringList() { + return mStringList; + } + + @DataClass.Generated.Member + public @NonNull Map<String,SampleWithCustomBuilder> getMap() { + return mMap; + } + + @DataClass.Generated.Member + public @NonNull Map<String,String> getStringMap() { + return mStringMap; + } + + @DataClass.Generated.Member + public @NonNull SparseArray<SampleWithCustomBuilder> getSparseArray() { + return mSparseArray; + } + + @DataClass.Generated.Member + public @NonNull SparseIntArray getSparseIntArray() { + return mSparseIntArray; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "ParcelAllTheThingsDataClass { " + + "stringArray = " + java.util.Arrays.toString(mStringArray) + ", " + + "intArray = " + java.util.Arrays.toString(mIntArray) + ", " + + "stringList = " + mStringList + ", " + + "map = " + mMap + ", " + + "stringMap = " + mStringMap + ", " + + "sparseArray = " + mSparseArray + ", " + + "sparseIntArray = " + mSparseIntArray + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeStringArray(mStringArray); + dest.writeIntArray(mIntArray); + dest.writeStringList(mStringList); + dest.writeMap(mMap); + dest.writeMap(mStringMap); + dest.writeSparseArray(mSparseArray); + dest.writeSparseIntArray(mSparseIntArray); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<ParcelAllTheThingsDataClass> CREATOR + = new Parcelable.Creator<ParcelAllTheThingsDataClass>() { + @Override + public ParcelAllTheThingsDataClass[] newArray(int size) { + return new ParcelAllTheThingsDataClass[size]; + } + + @Override + @SuppressWarnings({"unchecked", "RedundantCast"}) + public ParcelAllTheThingsDataClass createFromParcel(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String[] stringArray = in.createStringArray(); + int[] intArray = in.createIntArray(); + List<String> stringList = new java.util.ArrayList<>(); + in.readStringList(stringList); + Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>(); + in.readMap(map, SampleWithCustomBuilder.class.getClassLoader()); + Map<String,String> stringMap = new java.util.LinkedHashMap<>(); + in.readMap(stringMap, String.class.getClassLoader()); + SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader()); + SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray(); + return new ParcelAllTheThingsDataClass( + stringArray, + intArray, + stringList, + map, + stringMap, + sparseArray, + sparseIntArray); + } + }; + + /** + * A builder for {@link ParcelAllTheThingsDataClass} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static class Builder { + + private @NonNull String[] mStringArray; + private @NonNull int[] mIntArray; + private @NonNull List<String> mStringList; + private @NonNull Map<String,SampleWithCustomBuilder> mMap; + private @NonNull Map<String,String> mStringMap; + private @NonNull SparseArray<SampleWithCustomBuilder> mSparseArray; + private @NonNull SparseIntArray mSparseIntArray; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + @DataClass.Generated.Member + public @NonNull Builder setStringArray(@NonNull String... value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mStringArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setIntArray(@NonNull int... value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mIntArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setStringList(@NonNull List<String> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mStringList = value; + return this; + } + + /** @see #setStringList */ + @DataClass.Generated.Member + public @NonNull Builder addStringList(String value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mStringList == null) setStringList(new java.util.ArrayList<>()); + mStringList.add(value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setMap(@NonNull Map<String,SampleWithCustomBuilder> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mMap = value; + return this; + } + + /** @see #setMap */ + @DataClass.Generated.Member + public @NonNull Builder addMap(String key, SampleWithCustomBuilder value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mMap == null) setMap(new java.util.LinkedHashMap()); + mMap.put(key, value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setStringMap(@NonNull Map<String,String> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; + mStringMap = value; + return this; + } + + /** @see #setStringMap */ + @DataClass.Generated.Member + public @NonNull Builder addStringMap(String key, String value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mStringMap == null) setStringMap(new java.util.LinkedHashMap()); + mStringMap.put(key, value); + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setSparseArray(@NonNull SparseArray<SampleWithCustomBuilder> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x20; + mSparseArray = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setSparseIntArray(@NonNull SparseIntArray value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; + mSparseIntArray = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public ParcelAllTheThingsDataClass build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x80; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mStringArray = null; + } + if ((mBuilderFieldsSet & 0x2) == 0) { + mIntArray = null; + } + if ((mBuilderFieldsSet & 0x4) == 0) { + mStringList = null; + } + if ((mBuilderFieldsSet & 0x8) == 0) { + mMap = null; + } + if ((mBuilderFieldsSet & 0x10) == 0) { + mStringMap = null; + } + if ((mBuilderFieldsSet & 0x20) == 0) { + mSparseArray = null; + } + if ((mBuilderFieldsSet & 0x40) == 0) { + mSparseIntArray = null; + } + ParcelAllTheThingsDataClass o = new ParcelAllTheThingsDataClass( + mStringArray, + mIntArray, + mStringList, + mMap, + mStringMap, + mSparseArray, + mSparseIntArray); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x80) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1570139502128L, + codegenVersion = "1.0.4", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java", + inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)") + @Deprecated + private void __metadata() {} + +} diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index 66c7d06d6ff4..0631f7ded8ae 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -342,7 +342,7 @@ public final class SampleDataClass implements Parcelable { - // Code below generated by codegen v1.0.3. + // Code below generated by codegen v1.0.4. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -1798,8 +1798,8 @@ public final class SampleDataClass implements Parcelable { } @DataClass.Generated( - time = 1569956013899L, - codegenVersion = "1.0.3", + time = 1570139500112L, + codegenVersion = "1.0.4", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java index 663620743af9..c7a773530963 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java @@ -25,9 +25,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; + import android.net.LinkAddress; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.util.SparseArray; +import android.util.SparseIntArray; import androidx.test.runner.AndroidJUnit4; @@ -36,6 +41,9 @@ import org.junit.runner.RunWith; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** @@ -209,6 +217,32 @@ public class SampleDataClassTest { newBuilder().setDayOfWeek(42).build(); } + @Test + public void testDataStructures_parcelCorrectly() { + SampleWithCustomBuilder otherParcelable = new SampleWithCustomBuilder.Builder().setDelay(3, SECONDS).build(); + + ParcelAllTheThingsDataClass instance = new ParcelAllTheThingsDataClass.Builder() + .setIntArray(40, 41) + .addMap("foo", otherParcelable) + .setSparseArray(new SparseArray<SampleWithCustomBuilder>() {{ + put(45, otherParcelable); + }}) + .setSparseIntArray(new SparseIntArray() {{ + put(48, 49); + }}) + .addStringMap("foo2", "fooValue") + .setStringArray("foo", "bar") + .addStringList("foo") + .build(); + + ParcelAllTheThingsDataClass unparceledInstance = + parcelAndUnparcel(instance, ParcelAllTheThingsDataClass.CREATOR); + + // SparseArray and friends don't implement equals + // so just compare string representations instead + assertEquals(instance.toString(), unparceledInstance.toString()); + } + private static <T extends Parcelable> T parcelAndUnparcel( T original, Parcelable.Creator<T> creator) { Parcel p = Parcel.obtain(); diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java index c6bc8de3bb9e..0f8c663f5d4b 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -17,14 +17,16 @@ package com.android.codegentest; import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; import android.os.SystemClock; import com.android.internal.util.DataClass; import java.util.concurrent.TimeUnit; -@DataClass(genBuilder = true) -public class SampleWithCustomBuilder { +@DataClass(genBuilder = true, genAidl = false, genToString = true) +public class SampleWithCustomBuilder implements Parcelable { long delayAmount = 0; @NonNull @@ -73,8 +75,17 @@ public class SampleWithCustomBuilder { } + private static TimeUnit unparcelDelayUnit(Parcel p) { + return TimeUnit.values()[p.readInt()]; + } + + private void parcelDelayUnit(Parcel p, int flags) { + p.writeInt(delayUnit.ordinal()); + } - // Code below generated by codegen v1.0.3. + + + // Code below generated by codegen v1.0.4. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -112,6 +123,58 @@ public class SampleWithCustomBuilder { return creationTimestamp; } + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "SampleWithCustomBuilder { " + + "delayAmount = " + delayAmount + ", " + + "delayUnit = " + delayUnit + ", " + + "creationTimestamp = " + creationTimestamp + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeLong(delayAmount); + parcelDelayUnit(dest, flags); + dest.writeLong(creationTimestamp); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<SampleWithCustomBuilder> CREATOR + = new Parcelable.Creator<SampleWithCustomBuilder>() { + @Override + public SampleWithCustomBuilder[] newArray(int size) { + return new SampleWithCustomBuilder[size]; + } + + @Override + @SuppressWarnings({"unchecked", "RedundantCast"}) + public SampleWithCustomBuilder createFromParcel(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long _delayAmount = in.readLong(); + TimeUnit _delayUnit = unparcelDelayUnit(in); + long _creationTimestamp = in.readLong(); + return new SampleWithCustomBuilder( + _delayAmount, + _delayUnit, + _creationTimestamp); + } + }; + /** * A builder for {@link SampleWithCustomBuilder} */ @@ -176,10 +239,10 @@ public class SampleWithCustomBuilder { } @DataClass.Generated( - time = 1569956014908L, - codegenVersion = "1.0.3", + time = 1570139501160L, + codegenVersion = "1.0.4", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", - inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index 914e475cfe41..865340566019 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -341,7 +341,7 @@ private fun ClassPrinter.generateBuilderSetters(visibility: String) { } } - if (Type.contains("Map<")) { + if (FieldClass.endsWith("Map") && FieldInnerType != null) { generateBuilderMethod( name = adderName, defVisibility = visibility, @@ -533,7 +533,7 @@ fun ClassPrinter.generateParcelable() { } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && ParcelMethodsSuffix != "Parcelable") { - !"($Type) " + !"($FieldClass) " } } @@ -541,12 +541,15 @@ fun ClassPrinter.generateParcelable() { when { ParcelMethodsSuffix == "Parcelable" -> methodArgs += "$FieldClass.class.getClassLoader()" + ParcelMethodsSuffix == "SparseArray" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" ParcelMethodsSuffix == "TypedObject" -> methodArgs += "$FieldClass.CREATOR" ParcelMethodsSuffix == "TypedArray" -> methodArgs += "$FieldInnerClass.CREATOR" + ParcelMethodsSuffix == "Map" -> + methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" ParcelMethodsSuffix.startsWith("Parcelable") - || FieldClass == "Map" || (isList || isArray) && FieldInnerType !in PRIMITIVE_TYPES + "String" -> methodArgs += "$FieldInnerClass.class.getClassLoader()" diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 1e3973eaa022..1cc7ef338cc3 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.3" +const val CODEGEN_VERSION = "1.0.4" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" |