summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp6
-rw-r--r--apex/jobscheduler/framework/Android.bp9
-rw-r--r--apex/permission/Android.bp33
-rw-r--r--apex/permission/OWNERS6
-rw-r--r--apex/permission/apex_manifest.json4
-rw-r--r--apex/permission/com.android.permission.avbpubkeybin0 -> 1032 bytes
-rw-r--r--apex/permission/com.android.permission.pem51
-rw-r--r--apex/permission/com.android.permission.pk8bin0 -> 2376 bytes
-rw-r--r--apex/permission/com.android.permission.x509.pem35
-rw-r--r--api/current.txt13
-rw-r--r--api/system-current.txt3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java23
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/admin/PasswordMetrics.java45
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java15
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/autofill/SaveInfo.java101
-rw-r--r--core/java/android/service/euicc/EuiccService.java2
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java1
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl8
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl18
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java174
-rw-r--r--core/java/com/android/internal/widget/LockSettingsInternal.java4
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.aidl23
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.java102
-rw-r--r--core/java/com/android/server/SystemConfig.java10
-rw-r--r--core/proto/android/providers/settings/global.proto1
-rw-r--r--core/proto/android/server/notificationhistory.proto89
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java29
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java4
-rw-r--r--libs/hwui/renderthread/CanvasContext.h3
-rw-r--r--native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl6
-rw-r--r--native/android/surface_control.cpp2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java1
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java116
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java18
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java62
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/AndroidManifest.xml17
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java503
-rw-r--r--packages/Shell/src/com/android/shell/BugreportReceiver.java88
-rw-r--r--packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java67
-rw-r--r--packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java6
-rw-r--r--packages/SystemUI/res/layout/qqs_media_panel.xml100
-rw-r--r--packages/SystemUI/res/layout/qs_media_panel.xml124
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java (renamed from packages/SystemUI/src/com/android/systemui/ActivityBinder.java)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java (renamed from packages/SystemUI/src/com/android/systemui/ComponentBinder.java)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java (renamed from packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java (renamed from packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java (renamed from packages/SystemUI/src/com/android/systemui/DependencyBinder.java)5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java (renamed from packages/SystemUI/src/com/android/systemui/DependencyProvider.java)164
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java (renamed from packages/SystemUI/src/com/android/systemui/ServiceBinder.java)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java (renamed from packages/SystemUI/src/com/android/systemui/SystemUIBinder.java)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java (renamed from packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java)3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java (renamed from packages/SystemUI/src/com/android/systemui/SystemUIModule.java)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java (renamed from packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt133
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java301
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java203
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java19
-rw-r--r--services/art-profile145
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java18
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java6
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java18
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompatNative.java8
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java578
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java4
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java25
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java155
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java29
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java3
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java12
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java23
-rw-r--r--services/core/java/com/android/server/power/Notifier.java66
-rw-r--r--services/core/java/com/android/server/twilight/TwilightService.java25
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java28
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java67
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java36
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java315
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java295
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java143
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java111
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java81
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java27
-rw-r--r--telecomm/java/android/telecom/Call.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java12
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl15
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java66
-rw-r--r--wifi/tests/src/android/net/wifi/WifiInfoTest.java3
168 files changed, 3903 insertions, 2377 deletions
diff --git a/Android.bp b/Android.bp
index 6b2fb0c6b1ae..3b6eaa7a3afe 100644
--- a/Android.bp
+++ b/Android.bp
@@ -194,13 +194,14 @@ filegroup {
":framework-core-sources",
":framework-drm-sources",
":framework-graphics-sources",
+ ":framework-jobscheduler-sources", // jobscheduler is not a module for R
":framework-keystore-sources",
":framework-location-sources",
":framework-lowpan-sources",
- ":framework-media-sources",
":framework-mca-effect-sources",
":framework-mca-filterfw-sources",
":framework-mca-filterpacks-sources",
+ ":framework-media-sources",
":framework-mime-sources",
":framework-mms-sources",
":framework-opengl-sources",
@@ -410,7 +411,6 @@ java_library {
installable: true,
static_libs: [
"framework-minus-apex",
- "jobscheduler-framework",
],
required: [
"framework-platform-compat-config",
@@ -965,7 +965,6 @@ stubs_defaults {
":updatable-media-srcs",
"test-mock/src/**/*.java",
"test-runner/src/**/*.java",
- ":jobscheduler-framework-source",
],
libs: framework_docs_only_libs,
local_sourcepaths: frameworks_base_subdirs,
@@ -1028,7 +1027,6 @@ stubs_defaults {
":core-current-stubs-source",
":core_public_api_files",
":updatable-media-srcs",
- ":jobscheduler-framework-source",
],
libs: ["framework-internal-utils"],
local_sourcepaths: frameworks_base_subdirs,
diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp
index 621ff9a92bc5..3902aa212e32 100644
--- a/apex/jobscheduler/framework/Android.bp
+++ b/apex/jobscheduler/framework/Android.bp
@@ -1,5 +1,5 @@
filegroup {
- name: "jobscheduler-framework-source",
+ name: "framework-jobscheduler-sources",
srcs: [
"java/**/*.java",
"java/android/app/job/IJobCallback.aidl",
@@ -12,13 +12,12 @@ filegroup {
java_library {
name: "jobscheduler-framework",
- installable: true,
+ installable: false,
+ compile_dex: true,
sdk_version: "core_platform",
-
srcs: [
- ":jobscheduler-framework-source",
+ ":framework-jobscheduler-sources",
],
-
aidl: {
export_include_dirs: [
"java",
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
new file mode 100644
index 000000000000..027481401557
--- /dev/null
+++ b/apex/permission/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+apex {
+ name: "com.android.permission",
+
+ manifest: "apex_manifest.json",
+
+ key: "com.android.permission.key",
+ certificate: ":com.android.permission.certificate",
+}
+
+apex_key {
+ name: "com.android.permission.key",
+ public_key: "com.android.permission.avbpubkey",
+ private_key: "com.android.permission.pem",
+}
+
+android_app_certificate {
+ name: "com.android.permission.certificate",
+ certificate: "com.android.permission",
+}
diff --git a/apex/permission/OWNERS b/apex/permission/OWNERS
new file mode 100644
index 000000000000..957e10a582a0
--- /dev/null
+++ b/apex/permission/OWNERS
@@ -0,0 +1,6 @@
+svetoslavganov@google.com
+moltmann@google.com
+eugenesusla@google.com
+zhanghai@google.com
+evanseverson@google.com
+ntmyren@google.com
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
new file mode 100644
index 000000000000..2a8c4f737dff
--- /dev/null
+++ b/apex/permission/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.permission",
+ "version": 1
+}
diff --git a/apex/permission/com.android.permission.avbpubkey b/apex/permission/com.android.permission.avbpubkey
new file mode 100644
index 000000000000..9eaf85259637
--- /dev/null
+++ b/apex/permission/com.android.permission.avbpubkey
Binary files differ
diff --git a/apex/permission/com.android.permission.pem b/apex/permission/com.android.permission.pem
new file mode 100644
index 000000000000..3d584be5440d
--- /dev/null
+++ b/apex/permission/com.android.permission.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA6snt4eqoz85xiL9Sf6w1S1b9FgSHK05zYTh2JYPvQKQ3yeZp
+E6avJ6FN6XcbmkDzSd658BvUGDBSPhOlzuUO4BsoKBuLMxP6TxIQXFKidzDqY0vQ
+4qkS++bdIhUjwBP3OSZ3Czu0BiihK8GC75Abr//EyCyObGIGGfHEGANiOgrpP4X5
++OmLzQLCjk4iE1kg+U6cRSRI/XLaoWC0TvIIuzxznrQ6r5GmzgTOwyBWyIB+bj73
+bmsweHTU+w9Y7kGOx4hO3XCLIhoBWEw0EbuW9nZmQ4sZls5Jo/CbyJlCclF11yVo
+SCf2LG/T+9pah5NOmDQ1kPbU+0iKZIV4YFHGTIhyGDE/aPOuUT05ziCGDifgHr0u
+SG1x/RLqsVh/POvNxnvP9cQFMQ08BvbEJaTTgB785iwKsvdqCfmng/SAyxSetmzP
+StXVB3fh1OoZ8vunRbQYxnmUxycVqaA96zmBx2wLvbvzKo7pZFDE6nbhnT5+MRAM
+z/VIK89W26uB4gj8sBFslqZjT0jPqsAZuvDm7swOtMwIcEolyGJuFLqlhN7UwMz2
+9y8+IpYixR+HvD1TZI9NtmuCmv3kPrWgoMZg6yvaBayTIr8RdYzi6FO/C1lLiraz
+48dH3sXWRa8cgw6VcSUwYrEBIc3sotdsupO1iOjcFybIwaee0YTZJfjvbqkCAwEA
+AQKCAgEArRnfdpaJi1xLPGTCMDsIt9kUku0XswgN7PmxsYsKFAB+2S40/jYAIRm9
+1YjpItsMA8RgFfSOdJ77o6TctCMQyo17F8bm4+uwuic5RLfv7Cx2QmsdQF8jDfFx
+y7UGPJD7znjbf76uxXOjEB2FqZX3s9TAgkzHXIUQtoQW7RVhkCWHPjxKxgd5+NY2
+FrDoUpd9xhD9CcTsw1+wbRZdGW88nL6/B50dP2AFORM2VYo8MWr6y9FEn3YLsGOC
+uu7fxBk1aUrHyl81VRkTMMROB1zkuiUk1FtzrEm+5U15rXXBFYOVe9+qeLhtuOlh
+wueDoz0pzvF/JLe24uTik6YL0Ae6SD0pFXQ2KDrdH3cUHLok3r76/yGzaDNTFjS2
+2WbQ8dEJV8veNHk8gjGpFTJIsBUlcZpmUCDHlfvVMb3+2ahQ+28piQUt5t3zqJdZ
+NDqsOHzY6BRPc+Wm85Xii/lWiQceZSee/b1Enu+nchsyXhSenBfC6bIGZReyMI0K
+KKKuVhyR6OSOiR5ZdZ/NyXGqsWy05fn/h0X9hnpETsNaNYNKWvpHLfKll+STJpf7
+AZquJPIclQyiq5NONx6kfPztoCLkKV/zOgIj3Sx5oSZq+5gpO91nXWVwkTbqK1d1
+004q2Mah6UQyAk1XGQc2pHx7ouVcWawjU30vZ4C015Hv2lm/gVkCggEBAPltATYS
+OqOSL1YAtIHPiHxMjNAgUdglq8JiJFXVfkocGU9eNub3Ed3sSWu6GB9Myu/sSKje
+bJ5DZqxJnvB2Fqmu9I9OunLGFSD0aXs4prwsQ1Rm5FcbImtrxcciASdkoo8Pj0z4
+vk2r2NZD3VtER5Uh+YjSDkxcS9gBStXUpCL6gj69UpOxMmWqZVjyHatVB4lEvYJl
+N82uT7N7QVNL1DzcZ9z4C4r7ks1Pm7ka12s5m/oaAlAMdVeofiPJe1xA9zRToSr4
+tIbMkOeXFLVRLuji/7XsOgal5Rl59p+OwLshX5cswPVOMrH6zt+hbsJ5q8M5dqnX
+VAOBK7KNQ/EKZwcCggEBAPD6KVvyCim46n5EbcEqCkO7gevwZkw/9vLwmM5YsxTh
+z9FQkPO0iB7mwbX8w04I91Pre4NdfcgMG0pP1b13Sb4KHBchqW1a+TCs3kSGC6gn
+1SxmXHnA9jRxAkrWlGkoAQEz+aP61cXiiy2tXpQwJ8xQCKprfoqWZwhkCtEVU6CE
+S7v9cscOHIqgNxx4WoceMmq4EoihHAZzHxTcNVbByckMjb2XQJ0iNw3lDP4ddvc+
+a4HzHfHkhzeQ5ZNc8SvWU8z80aSCOKRsSD3aUTZzxhZ4O2tZSW7v7p+FpvVee7bC
+g8YCfszTdpVUMlLRLjScimAcovcFLSvtyupinxWg4M8CggEAN9YGEmOsSte7zwXj
+YrfhtumwEBtcFwX/2Ej+F1Tuq4p0xAa0RaoDjumJWhtTsRYQy/raHSuFpzwxbNoi
+QXQ+CIhI6RfXtz/OlQ0B2/rHoJJMFEXgUfuaDfAXW0eqeHYXyezSyIlamKqipPyW
+Pgsf9yue39keKEv1EorfhNTQVaA8rezV4oglXwrxGyNALw2e3UTNI7ai8mFWKDis
+XAg6n9E7UwUYGGnO6DUtCBgRJ0jDOQ6/e8n+LrxiWIKPIgzNCiK6jpMUXqTGv4Fb
+umdNGAdQ9RnHt5tFmRlrczaSwJFtA7uaCpAR2zPpQbiywchZAiAIB2dTwGEXNiZX
+kksg2wKCAQEA6pNad3qhkgPDoK6T+Jkn7M82paoaqtcJWWwEE7oceZNnbWZz9Agl
+CY+vuawXonrv5+0vCq2Tp4zBdBFLC2h3jFrjBVFrUFxifpOIukOSTVqZFON/2bWQ
+9XOcu6UuSz7522Xw+UNPnZXtzcUacD6AP08ZYGvLfrTyDyTzspyED5k48ALEHCkM
+d5WGkFxII4etpF0TDZVnZo/iDbhe49k4yFFEGO6Ho26PESOLBkNAb2V/2bwDxlij
+l9+g21Z6HiZA5SamHPH2mXgeyrcen1cL2QupK9J6vVcqfnboE6qp2zp2c+Yx8MlY
+gfy4EA44YFaSDQVTTgrn8f9Eq+zc130H2QKCAQEAqOKgv68nIPdDSngNyCVyWego
+boFiDaEJoBBg8FrBjTJ6wFLrNAnXmbvfTtgNmNAzF1cUPJZlIIsHgGrMCfpehbXq
+WQQIw+E+yFbTGLxseGRfsLrV0CsgnAoOVeod+yIHmqc3livaUbrWhL1V2f6Ue+sE
+7YLp/iP43NaMfA4kYk2ep7+ZJoEVkCjHJJaHWgAG3RynPJHkTJlSgu7wLYvGc9uE
+ZsEFUM46lX02t7rrtMfasVGrUy1c2xOxFb4v1vG6iEZ7+YWeq5o3AkxUwEGn+mG4
+/3p+k4AaTXJDXgyZ0Sv6CkGuPHenAYG4cswcUUEf/G4Ag77x6LBNMgycJBxUJA==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/permission/com.android.permission.pk8 b/apex/permission/com.android.permission.pk8
new file mode 100644
index 000000000000..d51673dbc2fc
--- /dev/null
+++ b/apex/permission/com.android.permission.pk8
Binary files differ
diff --git a/apex/permission/com.android.permission.x509.pem b/apex/permission/com.android.permission.x509.pem
new file mode 100644
index 000000000000..4b146c9edd4f
--- /dev/null
+++ b/apex/permission/com.android.permission.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKzCCBBOgAwIBAgIUezo3fQeVZsmLpm/dkpGWJ/G/MN8wDQYJKoZIhvcNAQEL
+BQAwgaMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMR8wHQYDVQQDDBZjb20uYW5kcm9pZC5wZXJtaXNzaW9uMSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MTAwOTIxMzExOVoYDzQ3NTcw
+OTA0MjEzMTE5WjCBozELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
+FjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNV
+BAsMB0FuZHJvaWQxHzAdBgNVBAMMFmNvbS5hbmRyb2lkLnBlcm1pc3Npb24xIjAg
+BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCxefguRJ7E6tBCTEOeU2HJEGs6AQQapLz9hMed0aaJ
+Qr7aTQiYJEk+sG4+jPYbjpxa8JDDzJHp+4g7DjfSb+dvT9n84A8lWaI/yRXTZTQN
+Hu5m/bgHhi0LbySpiaFyodXBKUAnOhZyGPtYjtBFywFylueub8ryc1Z6UxxU7udH
+1mkIr7sE48Qkq5SyjFROE96iFmYA+vS/JXOfS0NBHiMB4GBxx4V7kXpvrTI7hhZG
+HiyhKvNh7wyHIhO9nDEw1rwtAH6CsL3YkQEVBeAU98m+0Au+qStLYkKHh2l8zT4W
+7sVK1VSqfB+VqOUmeIGdzlBfqMsoXD+FJz6KnIdUHIwjFDjL7Xr+hd+7xve+Q3S+
+U3Blk/U6atY8PM09wNfilG+SvwcKk5IgriDcu3rWKgIFxbUUaxLrDW7pLlu6wt/d
+GGtKK+Bc0jF+9Z901Tl33i5xhc5yOktT0btkKs7lSeE6VzP/Nk5g0SuzixmuRoh9
+f5Ge41N2ZCEHNXx3wZeVZwHIIPfYrL7Yql1Xoxbfs4ETFk6ChzVQcvjfDQQuK58J
+uNc+TOCoI/qflXwGCwpuHl0ier8V5Z4tpMUl5rWyVR/QGRtLPvs2lLuxczDw1OXq
+wEVtCMn9aNnd4y7R9PZ52hi53HAvDjpWefrLYi+Q04J6iGFQ1qAFBClK9DquBvmR
+swIDAQABo1MwUTAdBgNVHQ4EFgQULpfus5s5SrqLkoUKyPXA0D1iHPMwHwYDVR0j
+BBgwFoAULpfus5s5SrqLkoUKyPXA0D1iHPMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAjxQG5EFv8V/9yV2glI53VOmlWMjfEgvUjd39s/XLyPlr
+OzPOKSB0NFo8To3l4l+MsManxPK8y0OyfEVKbWVz9onv0ovo5MVokBmV/2G0jmsV
+B4e9yjOq+DmqIvY/Qh63Ywb97sTgcFI8620MhQDbh2IpEGv4ZNV0H6rgXmgdSCBw
+1EjBoYfFpN5aMgZjeyzZcq+d1IapdWqdhuEJQkMvoYS4WIumNIJlEXPQRoq/F5Ih
+nszdbKI/jVyiGFa2oeZ3rja1Y6GCRU8TYEoKx1pjS8uQDOEDTwsG/QnUe9peEj0V
+SsCkIidJWTomAmq9Tub9vpBe1zuTpuRAwxwR0qwgSxozV1Mvow1dJ19oFtHX0yD6
+ZjCpRn5PW9kMvSWSlrcrFs1NJf0j1Cvf7bHpkEDqLqpMnnh9jaFQq3nzDY+MWcIR
+jDcgQpI+AiE2/qtauZnFEVhbce49nCnk9+5bpTTIZJdzqeaExe5KXHwEtZLaEDh4
+atLY9LuEvPsjmDIMOR6hycD9FvwGXhJOQBjESIWFwigtSb1Yud9n6201jw3MLJ4k
++WhkbmZgWy+xc+Mdm5H3XyB1lvHaHGkxu+QB9KyQuVQKwbUVcbwZIfTFPN6Zr/dS
+ZXJqAbBhG/dBgF0LazuLaPVpibi+a3Y+tb9b8eXGkz4F97PWZIEDkELQ+9KOvhc=
+-----END CERTIFICATE-----
diff --git a/api/current.txt b/api/current.txt
index 71dc58b70021..54d33a2c59b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6851,6 +6851,7 @@ package android.app.admin {
method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int);
+ method public void setLocationEnabled(@NonNull android.content.ComponentName, boolean);
method public void setLockTaskFeatures(@NonNull android.content.ComponentName, int);
method public void setLockTaskPackages(@NonNull android.content.ComponentName, @NonNull String[]) throws java.lang.SecurityException;
method public void setLogoutEnabled(@NonNull android.content.ComponentName, boolean);
@@ -29975,10 +29976,16 @@ package android.net.wifi {
method public String getSSID();
method public android.net.wifi.SupplicantState getSupplicantState();
method @IntRange(from=0xffffffff) public int getTxLinkSpeedMbps();
+ method public int getWifiTechnology();
method public void writeToParcel(android.os.Parcel, int);
field public static final String FREQUENCY_UNITS = "MHz";
field public static final String LINK_SPEED_UNITS = "Mbps";
field public static final int LINK_SPEED_UNKNOWN = -1; // 0xffffffff
+ field public static final int WIFI_TECHNOLOGY_11AC = 5; // 0x5
+ field public static final int WIFI_TECHNOLOGY_11AX = 6; // 0x6
+ field public static final int WIFI_TECHNOLOGY_11N = 4; // 0x4
+ field public static final int WIFI_TECHNOLOGY_LEGACY = 1; // 0x1
+ field public static final int WIFI_TECHNOLOGY_UNKNOWN = 0; // 0x0
}
public class WifiManager {
@@ -41368,11 +41375,16 @@ package android.service.autofill {
field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
+ field public static final int POSITIVE_BUTTON_STYLE_CONTINUE = 1; // 0x1
+ field public static final int POSITIVE_BUTTON_STYLE_SAVE = 0; // 0x0
field public static final int SAVE_DATA_TYPE_ADDRESS = 2; // 0x2
field public static final int SAVE_DATA_TYPE_CREDIT_CARD = 4; // 0x4
+ field public static final int SAVE_DATA_TYPE_DEBIT_CARD = 32; // 0x20
field public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 16; // 0x10
field public static final int SAVE_DATA_TYPE_GENERIC = 0; // 0x0
+ field public static final int SAVE_DATA_TYPE_GENERIC_CARD = 128; // 0x80
field public static final int SAVE_DATA_TYPE_PASSWORD = 1; // 0x1
+ field public static final int SAVE_DATA_TYPE_PAYMENT_CARD = 64; // 0x40
field public static final int SAVE_DATA_TYPE_USERNAME = 8; // 0x8
}
@@ -41386,6 +41398,7 @@ package android.service.autofill {
method @NonNull public android.service.autofill.SaveInfo.Builder setFlags(int);
method @NonNull public android.service.autofill.SaveInfo.Builder setNegativeAction(int, @Nullable android.content.IntentSender);
method @NonNull public android.service.autofill.SaveInfo.Builder setOptionalIds(@NonNull android.view.autofill.AutofillId[]);
+ method @NonNull public android.service.autofill.SaveInfo.Builder setPositiveAction(int);
method @NonNull public android.service.autofill.SaveInfo.Builder setTriggerId(@NonNull android.view.autofill.AutofillId);
method @NonNull public android.service.autofill.SaveInfo.Builder setValidator(@NonNull android.service.autofill.Validator);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index ad9a04d16a7e..10bcffc200ad 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8294,6 +8294,9 @@ package android.telephony {
public class TelephonyManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionReportDefaultNetworkStatus(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionResetAll(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionSetRadioEnabled(int, boolean);
method public int checkCarrierPrivilegesForPackage(String);
method public int checkCarrierPrivilegesForPackageAnyPhone(String);
method public void dial(String);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 375a06efba74..ad671dfcf80a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8351,6 +8351,24 @@ public class DevicePolicyManager {
}
/**
+ * Called by device owners to set the user's master location setting.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with
+ * @param locationEnabled whether location should be enabled or disabled
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void setLocationEnabled(@NonNull ComponentName admin, boolean locationEnabled) {
+ throwIfParentInstance("setLocationEnabled");
+ if (mService != null) {
+ try {
+ mService.setLocationEnabled(admin, locationEnabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Called by profile or device owners to update {@link android.provider.Settings.Secure}
* settings. Validation that the value of the setting is in the correct form for the setting
* type should be performed by the caller.
@@ -8379,6 +8397,11 @@ public class DevicePolicyManager {
* all users.
* </strong>
*
+ * <strong>Note: Starting from Android R, apps should no longer call this method with the
+ * setting {@link android.provider.Settings.Secure#LOCATION_MODE}, which is deprecated. Instead,
+ * device owners should call {@link #setLocationEnabled(ComponentName, boolean)}.
+ * </strong>
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param setting The name of the setting to update.
* @param value The value to update the setting to.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7d2c54ea1436..6b505223163c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -258,6 +258,8 @@ interface IDevicePolicyManager {
void setSystemSetting(in ComponentName who, in String setting, in String value);
void setSecureSetting(in ComponentName who, in String setting, in String value);
+ void setLocationEnabled(in ComponentName who, boolean locationEnabled);
+
boolean setTime(in ComponentName who, long millis);
boolean setTimeZone(in ComponentName who, String timeZone);
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index d9bfde5af61a..0ecfca74b26e 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -73,6 +73,11 @@ public final class PasswordMetrics implements Parcelable {
// consider it a complex PIN/password.
public static final int MAX_ALLOWED_SEQUENCE = 3;
+ // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN or CREDENTIAL_TYPE_PASSWORD.
+ // Note that this class still uses CREDENTIAL_TYPE_PASSWORD to represent both numeric PIN
+ // and alphabetic password. This is OK as long as this definition is only used internally,
+ // and the value never gets mixed up with credential types from other parts of the framework.
+ // TODO: fix this (ideally after we move logic to PasswordPolicy)
public @CredentialType int credType;
// Fields below only make sense when credType is PASSWORD.
public int length = 0;
@@ -161,24 +166,26 @@ public final class PasswordMetrics implements Parcelable {
public static final @NonNull Parcelable.Creator<PasswordMetrics> CREATOR
= new Parcelable.Creator<PasswordMetrics>() {
- public PasswordMetrics createFromParcel(Parcel in) {
- int credType = in.readInt();
- int length = in.readInt();
- int letters = in.readInt();
- int upperCase = in.readInt();
- int lowerCase = in.readInt();
- int numeric = in.readInt();
- int symbols = in.readInt();
- int nonLetter = in.readInt();
- int nonNumeric = in.readInt();
- int seqLength = in.readInt();
- return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, numeric,
- symbols, nonLetter, nonNumeric, seqLength);
- }
-
- public PasswordMetrics[] newArray(int size) {
- return new PasswordMetrics[size];
- }
+ @Override
+ public PasswordMetrics createFromParcel(Parcel in) {
+ int credType = in.readInt();
+ int length = in.readInt();
+ int letters = in.readInt();
+ int upperCase = in.readInt();
+ int lowerCase = in.readInt();
+ int numeric = in.readInt();
+ int symbols = in.readInt();
+ int nonLetter = in.readInt();
+ int nonNumeric = in.readInt();
+ int seqLength = in.readInt();
+ return new PasswordMetrics(credType, length, letters, upperCase, lowerCase,
+ numeric, symbols, nonLetter, nonNumeric, seqLength);
+ }
+
+ @Override
+ public PasswordMetrics[] newArray(int size) {
+ return new PasswordMetrics[size];
+ }
};
/**
@@ -189,7 +196,7 @@ public final class PasswordMetrics implements Parcelable {
* {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}.
*/
public static PasswordMetrics computeForCredential(LockscreenCredential credential) {
- if (credential.isPassword()) {
+ if (credential.isPassword() || credential.isPin()) {
return PasswordMetrics.computeForPassword(credential.getCredential());
} else if (credential.isPattern()) {
return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 83391f368ac1..43842c5c3403 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -94,6 +94,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
/**
* InputMethodService provides a standard implementation of an InputMethod,
@@ -434,6 +435,7 @@ public class InputMethodService extends AbstractInputMethodService {
final int[] mTmpLocation = new int[2];
final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> {
+ onComputeInsets(mTmpInsets);
if (isExtractViewShown()) {
// In true fullscreen mode, we just say the window isn't covering
// any content so we don't impact whatever is behind.
@@ -442,12 +444,15 @@ public class InputMethodService extends AbstractInputMethodService {
info.touchableRegion.setEmpty();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
} else {
- onComputeInsets(mTmpInsets);
info.contentInsets.top = mTmpInsets.contentTopInsets;
info.visibleInsets.top = mTmpInsets.visibleTopInsets;
info.touchableRegion.set(mTmpInsets.touchableRegion);
info.setTouchableInsets(mTmpInsets.touchableInsets);
}
+
+ if (mInputFrame != null) {
+ setImeExclusionRect(mTmpInsets.visibleTopInsets);
+ }
};
final View.OnClickListener mActionClickListener = v -> {
@@ -672,6 +677,14 @@ public class InputMethodService extends AbstractInputMethodService {
mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition);
}
+ /** Set region of the keyboard to be avoided from back gesture */
+ private void setImeExclusionRect(int visibleTopInsets) {
+ View inputFrameRootView = mInputFrame.getRootView();
+ Rect r = new Rect(0, visibleTopInsets, inputFrameRootView.getWidth(),
+ inputFrameRootView.getHeight());
+ inputFrameRootView.setSystemGestureExclusionRects(Collections.singletonList(r));
+ }
+
/**
* Concrete implementation of
* {@link AbstractInputMethodService.AbstractInputMethodSessionImpl} that provides
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bdc78342d42a..cff99f34126a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8594,13 +8594,19 @@ public final class Settings {
public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
/**
- * URI for the "wireless charging started" and "wired charging started" sound.
+ * URI for the "wireless charging started" sound.
* @hide
*/
- public static final String CHARGING_STARTED_SOUND =
+ public static final String WIRELESS_CHARGING_STARTED_SOUND =
"wireless_charging_started_sound";
/**
+ * URI for "wired charging started" sound.
+ * @hide
+ */
+ public static final String CHARGING_STARTED_SOUND = "charging_started_sound";
+
+ /**
* Whether to play a sound for charging events.
* @deprecated Use {@link android.provider.Settings.Secure#CHARGING_SOUNDS_ENABLED} instead
* @hide
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 94b9d050a44d..48ba4295f3c8 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -181,6 +181,23 @@ public final class SaveInfo implements Parcelable {
public static final int SAVE_DATA_TYPE_EMAIL_ADDRESS = 0x10;
/**
+ * Type used when the {@link FillResponse} represents a debit card.
+ */
+ public static final int SAVE_DATA_TYPE_DEBIT_CARD = 0x20;
+
+ /**
+ * Type used when the {@link FillResponse} represents a payment card except for credit and
+ * debit cards.
+ */
+ public static final int SAVE_DATA_TYPE_PAYMENT_CARD = 0x40;
+
+ /**
+ * Type used when the {@link FillResponse} represents a card that does not a specified card or
+ * cannot identify what the card is for.
+ */
+ public static final int SAVE_DATA_TYPE_GENERIC_CARD = 0x80;
+
+ /**
* Style for the negative button of the save UI to cancel the
* save operation. In this case, the user tapping the negative
* button signals that they would prefer to not save the filled
@@ -207,6 +224,30 @@ public final class SaveInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@interface NegativeButtonStyle{}
+ /**
+ * Style for the positive button of save UI to request the save operation.
+ * In this case, the user tapping the positive button signals that they
+ * agrees to save the filled content.
+ */
+ public static final int POSITIVE_BUTTON_STYLE_SAVE = 0;
+
+ /**
+ * Style for the positive button of save UI to have next action before the save operation.
+ * This could be useful if the filled content contains sensitive personally identifiable
+ * information and then requires user confirmation or verification. In this case, the user
+ * tapping the positive button signals that they would complete the next required action
+ * to save the filled content.
+ */
+ public static final int POSITIVE_BUTTON_STYLE_CONTINUE = 1;
+
+ /** @hide */
+ @IntDef(prefix = { "POSITIVE_BUTTON_STYLE_" }, value = {
+ POSITIVE_BUTTON_STYLE_SAVE,
+ POSITIVE_BUTTON_STYLE_CONTINUE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PositiveButtonStyle{}
+
/** @hide */
@IntDef(flag = true, prefix = { "SAVE_DATA_TYPE_" }, value = {
SAVE_DATA_TYPE_GENERIC,
@@ -214,7 +255,10 @@ public final class SaveInfo implements Parcelable {
SAVE_DATA_TYPE_ADDRESS,
SAVE_DATA_TYPE_CREDIT_CARD,
SAVE_DATA_TYPE_USERNAME,
- SAVE_DATA_TYPE_EMAIL_ADDRESS
+ SAVE_DATA_TYPE_EMAIL_ADDRESS,
+ SAVE_DATA_TYPE_DEBIT_CARD,
+ SAVE_DATA_TYPE_PAYMENT_CARD,
+ SAVE_DATA_TYPE_GENERIC_CARD
})
@Retention(RetentionPolicy.SOURCE)
@interface SaveDataType{}
@@ -266,6 +310,7 @@ public final class SaveInfo implements Parcelable {
private final @SaveDataType int mType;
private final @NegativeButtonStyle int mNegativeButtonStyle;
+ private final @PositiveButtonStyle int mPositiveButtonStyle;
private final IntentSender mNegativeActionListener;
private final AutofillId[] mRequiredIds;
private final AutofillId[] mOptionalIds;
@@ -281,6 +326,7 @@ public final class SaveInfo implements Parcelable {
mType = builder.mType;
mNegativeButtonStyle = builder.mNegativeButtonStyle;
mNegativeActionListener = builder.mNegativeActionListener;
+ mPositiveButtonStyle = builder.mPositiveButtonStyle;
mRequiredIds = builder.mRequiredIds;
mOptionalIds = builder.mOptionalIds;
mDescription = builder.mDescription;
@@ -313,6 +359,11 @@ public final class SaveInfo implements Parcelable {
}
/** @hide */
+ public @PositiveButtonStyle int getPositiveActionStyle() {
+ return mPositiveButtonStyle;
+ }
+
+ /** @hide */
public @Nullable AutofillId[] getRequiredIds() {
return mRequiredIds;
}
@@ -374,6 +425,7 @@ public final class SaveInfo implements Parcelable {
private final @SaveDataType int mType;
private @NegativeButtonStyle int mNegativeButtonStyle = NEGATIVE_BUTTON_STYLE_CANCEL;
+ private @PositiveButtonStyle int mPositiveButtonStyle = POSITIVE_BUTTON_STYLE_SAVE;
private IntentSender mNegativeActionListener;
private final AutofillId[] mRequiredIds;
private AutofillId[] mOptionalIds;
@@ -394,8 +446,9 @@ public final class SaveInfo implements Parcelable {
* can be any combination of {@link SaveInfo#SAVE_DATA_TYPE_GENERIC},
* {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD},
* {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD},
- * {@link SaveInfo#SAVE_DATA_TYPE_USERNAME}, or
- * {@link SaveInfo#SAVE_DATA_TYPE_EMAIL_ADDRESS}.
+ * {@link SaveInfo#SAVE_DATA_TYPE_DEBIT_CARD}, {@link SaveInfo#SAVE_DATA_TYPE_PAYMENT_CARD},
+ * {@link SaveInfo#SAVE_DATA_TYPE_GENERIC_CARD}, {@link SaveInfo#SAVE_DATA_TYPE_USERNAME},
+ * or {@link SaveInfo#SAVE_DATA_TYPE_EMAIL_ADDRESS}.
* @param requiredIds ids of all required views that will trigger a save request.
*
* <p>See {@link SaveInfo} for more info.
@@ -418,8 +471,9 @@ public final class SaveInfo implements Parcelable {
* can be any combination of {@link SaveInfo#SAVE_DATA_TYPE_GENERIC},
* {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD},
* {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD},
- * {@link SaveInfo#SAVE_DATA_TYPE_USERNAME}, or
- * {@link SaveInfo#SAVE_DATA_TYPE_EMAIL_ADDRESS}.
+ * {@link SaveInfo#SAVE_DATA_TYPE_DEBIT_CARD}, {@link SaveInfo#SAVE_DATA_TYPE_PAYMENT_CARD},
+ * {@link SaveInfo#SAVE_DATA_TYPE_GENERIC_CARD}, {@link SaveInfo#SAVE_DATA_TYPE_USERNAME},
+ * or {@link SaveInfo#SAVE_DATA_TYPE_EMAIL_ADDRESS}.
*
* <p>See {@link SaveInfo} for more info.
*/
@@ -523,6 +577,8 @@ public final class SaveInfo implements Parcelable {
public @NonNull Builder setNegativeAction(@NegativeButtonStyle int style,
@Nullable IntentSender listener) {
throwIfDestroyed();
+ Preconditions.checkArgumentInRange(style, NEGATIVE_BUTTON_STYLE_CANCEL,
+ NEGATIVE_BUTTON_STYLE_REJECT, "style");
if (style != NEGATIVE_BUTTON_STYLE_CANCEL
&& style != NEGATIVE_BUTTON_STYLE_REJECT) {
throw new IllegalArgumentException("Invalid style: " + style);
@@ -533,6 +589,33 @@ public final class SaveInfo implements Parcelable {
}
/**
+ * Sets the style for the positive save action.
+ *
+ * <p>This allows an autofill service to customize the style of the
+ * positive action in the save UI. Note that selecting the positive
+ * action regardless of its style would dismiss the save UI and calling
+ * into the {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) save request}.
+ * The service should take the next action if selecting style
+ * {@link #POSITIVE_BUTTON_STYLE_CONTINUE}. The default style is
+ * {@link #POSITIVE_BUTTON_STYLE_SAVE}
+ *
+ * @param style The action style.
+ * @return This builder.
+ *
+ * @see #POSITIVE_BUTTON_STYLE_SAVE
+ * @see #POSITIVE_BUTTON_STYLE_CONTINUE
+ *
+ * @throws IllegalArgumentException If the style is invalid
+ */
+ public @NonNull Builder setPositiveAction(@PositiveButtonStyle int style) {
+ throwIfDestroyed();
+ Preconditions.checkArgumentInRange(style, POSITIVE_BUTTON_STYLE_SAVE,
+ POSITIVE_BUTTON_STYLE_CONTINUE, "style");
+ mPositiveButtonStyle = style;
+ return this;
+ }
+
+ /**
* Sets an object used to validate the user input - if the input is not valid, the
* autofill save UI is not shown.
*
@@ -717,8 +800,10 @@ public final class SaveInfo implements Parcelable {
final StringBuilder builder = new StringBuilder("SaveInfo: [type=")
.append(DebugUtils.flagsToString(SaveInfo.class, "SAVE_DATA_TYPE_", mType))
.append(", requiredIds=").append(Arrays.toString(mRequiredIds))
- .append(", style=").append(DebugUtils.flagsToString(SaveInfo.class,
- "NEGATIVE_BUTTON_STYLE_", mNegativeButtonStyle));
+ .append(", negative style=").append(DebugUtils.flagsToString(SaveInfo.class,
+ "NEGATIVE_BUTTON_STYLE_", mNegativeButtonStyle))
+ .append(", positive style=").append(DebugUtils.flagsToString(SaveInfo.class,
+ "POSITIVE_BUTTON_STYLE_", mPositiveButtonStyle));
if (mOptionalIds != null) {
builder.append(", optionalIds=").append(Arrays.toString(mOptionalIds));
}
@@ -763,6 +848,7 @@ public final class SaveInfo implements Parcelable {
parcel.writeParcelableArray(mOptionalIds, flags);
parcel.writeInt(mNegativeButtonStyle);
parcel.writeParcelable(mNegativeActionListener, flags);
+ parcel.writeInt(mPositiveButtonStyle);
parcel.writeCharSequence(mDescription);
parcel.writeParcelable(mCustomDescription, flags);
parcel.writeParcelable(mValidator, flags);
@@ -794,6 +880,7 @@ public final class SaveInfo implements Parcelable {
}
builder.setNegativeAction(parcel.readInt(), parcel.readParcelable(null));
+ builder.setPositiveAction(parcel.readInt());
builder.setDescription(parcel.readCharSequence());
final CustomDescription customDescripton = parcel.readParcelable(null);
if (customDescripton != null) {
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 8a9f68942e9d..12c25806d666 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -516,7 +516,7 @@ public abstract class EuiccService extends Service {
* @see android.telephony.euicc.EuiccManager#eraseSubscriptions
*
* @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
- * and use @link{onEraseSubscriptionsWithOptions} instead
+ * and use {@link #onEraseSubscriptionsWithOptions(int, int)} instead
*/
@Deprecated
public abstract int onEraseSubscriptions(int slotId);
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index b9a92b58768c..28a8a8631372 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -274,6 +274,7 @@ public class ResolverListController {
// Fall into normal sort when number of ranked elements
// needed is not smaller than size of input list.
sort(inputList);
+ return;
}
try {
long beforeRank = System.currentTimeMillis();
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 4099cfa51b33..8391ad2f12c2 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -49,9 +49,10 @@ interface IPlatformCompat
* 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 userId The ID of the user that the operation is done for.
* @param packageName The package name of the app in question.
*/
- void reportChangeByPackageName(long changeId, in String packageName);
+ void reportChangeByPackageName(long changeId, in String packageName, int userId);
/**
* Reports that a compatibility change is affecting an app process now.
@@ -86,7 +87,7 @@ interface IPlatformCompat
* be called when implementing functionality on behalf of the affected app.
*
* <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name
- * instead of an {@link ApplicationInfo}
+ * and userId 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.
*
@@ -100,9 +101,10 @@ interface IPlatformCompat
*
* @param changeId The ID of the compatibility change in question.
* @param packageName The package name of the app in question.
+ * @param userId The ID of the user that the operation is done for.
* @return {@code true} if the change is enabled for the current app.
*/
- boolean isChangeEnabledByPackageName(long changeId, in String packageName);
+ boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
/**
* Query if a given compatibility change is enabled for an app process. This method should
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index b626fc6e0608..897b982406dc 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -24,6 +24,7 @@ import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.RecoveryCertPath;
import com.android.internal.widget.ICheckCredentialProgressCallback;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import java.util.Map;
@@ -42,19 +43,16 @@ interface ILockSettings {
long getLong(in String key, in long defaultValue, in int userId);
@UnsupportedAppUsage
String getString(in String key, in String defaultValue, in int userId);
- boolean setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange);
+ boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange);
void resetKeyStore(int userId);
- VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
+ VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId,
in ICheckCredentialProgressCallback progressCallback);
- VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId);
- VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId);
+ VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, long challenge, int userId);
+ VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, long challenge, int userId);
boolean checkVoldPassword(int userId);
- @UnsupportedAppUsage
- boolean havePattern(int userId);
- @UnsupportedAppUsage
- boolean havePassword(int userId);
- byte[] getHashFactor(in byte[] currentCredential, int userId);
- void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword);
+ int getCredentialType(int userId);
+ byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
+ void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
boolean getSeparateProfileChallengeEnabled(int userId);
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 7a42985c7402..b534213ec859 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,9 +17,6 @@
package com.android.internal.widget;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
@@ -59,10 +56,10 @@ import android.util.SparseLongArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import libcore.util.HexEncoding;
-
import com.google.android.collect.Lists;
+import libcore.util.HexEncoding;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.MessageDigest;
@@ -117,13 +114,19 @@ public class LockPatternUtils {
// NOTE: When modifying this, make sure credential sufficiency validation logic is intact.
public static final int CREDENTIAL_TYPE_NONE = -1;
public static final int CREDENTIAL_TYPE_PATTERN = 1;
- public static final int CREDENTIAL_TYPE_PASSWORD = 2;
+ // This is the legacy value persisted on disk. Never return it to clients, but internally
+ // we still need it to handle upgrade cases.
+ public static final int CREDENTIAL_TYPE_PASSWORD_OR_PIN = 2;
+ public static final int CREDENTIAL_TYPE_PIN = 3;
+ public static final int CREDENTIAL_TYPE_PASSWORD = 4;
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"CREDENTIAL_TYPE_"}, value = {
CREDENTIAL_TYPE_NONE,
CREDENTIAL_TYPE_PATTERN,
- CREDENTIAL_TYPE_PASSWORD, // Either pin or password.
+ CREDENTIAL_TYPE_PASSWORD,
+ CREDENTIAL_TYPE_PIN,
+ // CREDENTIAL_TYPE_PASSWORD_OR_PIN is missing on purpose.
})
public @interface CredentialType {}
@@ -169,6 +172,7 @@ public class LockPatternUtils {
public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle";
public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp";
+ public static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
private static final String HISTORY_DELIMITER = ",";
@UnsupportedAppUsage
@@ -372,8 +376,8 @@ public class LockPatternUtils {
*
* @param credential The credential to check.
* @param challenge The challenge to verify against the credential
- * @return the attestation that the challenge was verified, or null
* @param userId The user whose credential is being verified
+ * @return the attestation that the challenge was verified, or null
* @throws RequestThrottledException if credential verification is being throttled due to
* to many incorrect attempts.
* @throws IllegalStateException if called on the main thread.
@@ -383,7 +387,7 @@ public class LockPatternUtils {
throwIfCalledOnMainThread();
try {
VerifyCredentialResponse response = getLockSettings().verifyCredential(
- credential.getCredential(), credential.getType(), challenge, userId);
+ credential, challenge, userId);
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return response.getPayload();
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
@@ -392,6 +396,7 @@ public class LockPatternUtils {
return null;
}
} catch (RemoteException re) {
+ Log.e(TAG, "failed to verify credential", re);
return null;
}
}
@@ -413,8 +418,7 @@ public class LockPatternUtils {
throwIfCalledOnMainThread();
try {
VerifyCredentialResponse response = getLockSettings().checkCredential(
- credential.getCredential(), credential.getType(),
- userId, wrapCallback(progressCallback));
+ credential, userId, wrapCallback(progressCallback));
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return true;
@@ -424,6 +428,7 @@ public class LockPatternUtils {
return false;
}
} catch (RemoteException re) {
+ Log.e(TAG, "failed to check credential", re);
return false;
}
}
@@ -447,8 +452,7 @@ public class LockPatternUtils {
throwIfCalledOnMainThread();
try {
VerifyCredentialResponse response =
- getLockSettings().verifyTiedProfileChallenge(
- credential.getCredential(), credential.getType(), challenge, userId);
+ getLockSettings().verifyTiedProfileChallenge(credential, challenge, userId);
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return response.getPayload();
@@ -458,6 +462,7 @@ public class LockPatternUtils {
return null;
}
} catch (RemoteException re) {
+ Log.e(TAG, "failed to verify tied profile credential", re);
return null;
}
}
@@ -471,6 +476,7 @@ public class LockPatternUtils {
try {
return getLockSettings().checkVoldPassword(userId);
} catch (RemoteException re) {
+ Log.e(TAG, "failed to check vold password", re);
return false;
}
}
@@ -482,7 +488,7 @@ public class LockPatternUtils {
public byte[] getPasswordHistoryHashFactor(@NonNull LockscreenCredential currentPassword,
int userId) {
try {
- return getLockSettings().getHashFactor(currentPassword.getCredential(), userId);
+ return getLockSettings().getHashFactor(currentPassword, userId);
} catch (RemoteException e) {
Log.e(TAG, "failed to get hash factor", e);
return null;
@@ -524,30 +530,6 @@ public class LockPatternUtils {
}
/**
- * Check to see if the user has stored a lock pattern.
- * @return Whether a saved pattern exists.
- */
- private boolean savedPatternExists(int userId) {
- try {
- return getLockSettings().havePattern(userId);
- } catch (RemoteException re) {
- return false;
- }
- }
-
- /**
- * Check to see if the user has stored a lock pattern.
- * @return Whether a saved pattern exists.
- */
- private boolean savedPasswordExists(int userId) {
- try {
- return getLockSettings().havePassword(userId);
- } catch (RemoteException re) {
- return false;
- }
- }
-
- /**
* Return true if the user has ever chosen a pattern. This is true even if the pattern is
* currently cleared.
*
@@ -568,22 +550,11 @@ public class LockPatternUtils {
/**
* Used by device policy manager to validate the current password
* information it has.
+ * @Deprecated use {@link #getKeyguardStoredPasswordQuality}
*/
@UnsupportedAppUsage
public int getActivePasswordQuality(int userId) {
- int quality = getKeyguardStoredPasswordQuality(userId);
-
- if (isLockPasswordEnabled(quality, userId)) {
- // Quality is a password and a password exists. Return the quality.
- return quality;
- }
-
- if (isLockPatternEnabled(quality, userId)) {
- // Quality is a pattern and a pattern exists. Return the quality.
- return quality;
- }
-
- return PASSWORD_QUALITY_UNSPECIFIED;
+ return getKeyguardStoredPasswordQuality(userId);
}
/**
@@ -641,6 +612,22 @@ public class LockPatternUtils {
return quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
}
+ /** Returns the canonical password quality corresponding to the given credential type. */
+ public static int credentialTypeToPasswordQuality(int credentialType) {
+ switch (credentialType) {
+ case CREDENTIAL_TYPE_NONE:
+ return PASSWORD_QUALITY_UNSPECIFIED;
+ case CREDENTIAL_TYPE_PATTERN:
+ return PASSWORD_QUALITY_SOMETHING;
+ case CREDENTIAL_TYPE_PIN:
+ return PASSWORD_QUALITY_NUMERIC;
+ case CREDENTIAL_TYPE_PASSWORD:
+ return PASSWORD_QUALITY_ALPHABETIC;
+ default:
+ throw new IllegalStateException("Unknown type: " + credentialType);
+ }
+ }
+
/**
* Save a new lockscreen credential.
*
@@ -684,19 +671,12 @@ public class LockPatternUtils {
}
newCredential.checkLength();
- final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
- setKeyguardStoredPasswordQuality(newCredential.getQuality(), userHandle);
-
try {
if (!getLockSettings().setLockCredential(
- newCredential.getCredential(), newCredential.getType(),
- savedCredential.getCredential(),
- newCredential.getQuality(), userHandle, allowUntrustedChange)) {
- setKeyguardStoredPasswordQuality(currentQuality, userHandle);
+ newCredential, savedCredential, userHandle, allowUntrustedChange)) {
return false;
}
- } catch (RemoteException | RuntimeException e) {
- setKeyguardStoredPasswordQuality(currentQuality, userHandle);
+ } catch (RemoteException e) {
throw new RuntimeException("Unable to save lock password", e);
}
@@ -904,14 +884,12 @@ public class LockPatternUtils {
* @see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)
*
* @return stored password quality
+ * @deprecated use {@link #getCredentialTypeForUser(int)} instead
*/
@UnsupportedAppUsage
+ @Deprecated
public int getKeyguardStoredPasswordQuality(int userHandle) {
- return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
- }
-
- private void setKeyguardStoredPasswordQuality(int quality, int userHandle) {
- setLong(PASSWORD_TYPE_KEY, quality, userHandle);
+ return credentialTypeToPasswordQuality(getCredentialTypeForUser(userHandle));
}
/**
@@ -920,17 +898,17 @@ public class LockPatternUtils {
*
* @param userHandle Managed profile user id
* @param enabled True if separate challenge is enabled
- * @param managedUserPassword Managed profile previous password. Null when {@code enabled} is
+ * @param profilePassword Managed profile previous password. Null when {@code enabled} is
* true
*/
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
- LockscreenCredential managedUserPassword) {
+ LockscreenCredential profilePassword) {
if (!isManagedProfile(userHandle)) {
return;
}
try {
getLockSettings().setSeparateProfileChallengeEnabled(userHandle, enabled,
- managedUserPassword.getCredential());
+ profilePassword);
reportEnabledTrustAgentsChanged(userHandle);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't update work profile challenge enabled");
@@ -1098,28 +1076,33 @@ public class LockPatternUtils {
}
/**
+ * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
+ * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
+ * {@link #CREDENTIAL_TYPE_PASSWORD}
+ */
+ public @CredentialType int getCredentialTypeForUser(int userHandle) {
+ try {
+ return getLockSettings().getCredentialType(userHandle);
+ } catch (RemoteException re) {
+ Log.e(TAG, "failed to get credential type", re);
+ return CREDENTIAL_TYPE_NONE;
+ }
+ }
+
+ /**
* @param userId the user for which to report the value
* @return Whether the lock screen is secured.
*/
@UnsupportedAppUsage
public boolean isSecure(int userId) {
- int mode = getKeyguardStoredPasswordQuality(userId);
- return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId);
+ int type = getCredentialTypeForUser(userId);
+ return type != CREDENTIAL_TYPE_NONE;
}
@UnsupportedAppUsage
public boolean isLockPasswordEnabled(int userId) {
- return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId);
- }
-
- private boolean isLockPasswordEnabled(int mode, int userId) {
- final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC
- || mode == PASSWORD_QUALITY_NUMERIC
- || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX
- || mode == PASSWORD_QUALITY_ALPHANUMERIC
- || mode == PASSWORD_QUALITY_COMPLEX
- || mode == PASSWORD_QUALITY_MANAGED;
- return passwordEnabled && savedPasswordExists(userId);
+ int type = getCredentialTypeForUser(userId);
+ return type == CREDENTIAL_TYPE_PASSWORD || type == CREDENTIAL_TYPE_PIN;
}
/**
@@ -1127,7 +1110,8 @@ public class LockPatternUtils {
*/
@UnsupportedAppUsage
public boolean isLockPatternEnabled(int userId) {
- return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId);
+ int type = getCredentialTypeForUser(userId);
+ return type == CREDENTIAL_TYPE_PATTERN;
}
@Deprecated
@@ -1143,10 +1127,6 @@ public class LockPatternUtils {
setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId);
}
- private boolean isLockPatternEnabled(int mode, int userId) {
- return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId);
- }
-
/**
* @return Whether the visible pattern is enabled.
*/
@@ -1543,8 +1523,8 @@ public class LockPatternUtils {
* @param userHandle The user who's lock credential to be changed
* @return {@code true} if the operation is successful.
*/
- public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
- byte[] token, int userHandle) {
+ public boolean setLockCredentialWithToken(@NonNull LockscreenCredential credential,
+ long tokenHandle, byte[] token, int userHandle) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
@@ -1552,19 +1532,8 @@ public class LockPatternUtils {
credential.checkLength();
LockSettingsInternal localService = getLockSettingsInternal();
- final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
- setKeyguardStoredPasswordQuality(credential.getQuality(), userHandle);
-
- try {
- if (!localService.setLockCredentialWithToken(credential.getCredential(),
- credential.getType(),
- tokenHandle, token, credential.getQuality(), userHandle)) {
- setKeyguardStoredPasswordQuality(currentQuality, userHandle);
- return false;
- }
- } catch (RuntimeException e) {
- setKeyguardStoredPasswordQuality(currentQuality, userHandle);
- throw new RuntimeException("Unable to save lock credential", e);
+ if (!localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle)) {
+ return false;
}
onPostPasswordChanged(credential, userHandle);
@@ -1765,7 +1734,8 @@ public class LockPatternUtils {
}
public boolean isSyntheticPasswordEnabled() {
- return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
+ return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT,
+ UserHandle.USER_SYSTEM) != 0;
}
/**
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index aab2f4b288b2..dd05576338ef 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -59,8 +59,8 @@ public abstract class LockSettingsInternal {
*
* @return true if password is set.
*/
- public abstract boolean setLockCredentialWithToken(byte[] credential, int type,
- long tokenHandle, byte[] token, int requestedQuality, int userId);
+ public abstract boolean setLockCredentialWithToken(LockscreenCredential credential,
+ long tokenHandle, byte[] token, int userId);
public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.aidl b/core/java/com/android/internal/widget/LockscreenCredential.aidl
new file mode 100644
index 000000000000..22501ff5a562
--- /dev/null
+++ b/core/java/com/android/internal/widget/LockscreenCredential.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.widget;
+
+/**
+ * A class representing a lockscreen credential.
+ */
+parcelable LockscreenCredential;
+
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 19e6d97eaa06..f456349a8937 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -16,14 +16,11 @@
package com.android.internal.widget;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -61,9 +58,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
// Stores raw credential bytes, or null if credential has been zeroized. An empty password
// is represented as a byte array of length 0.
private byte[] mCredential;
- // Store the quality of the password, this is used to distinguish between pin
- // (PASSWORD_QUALITY_NUMERIC) and password (PASSWORD_QUALITY_ALPHABETIC).
- private final int mQuality;
/**
* Private constructor, use static builder methods instead.
@@ -72,15 +66,18 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
* LockscreenCredential will only store the reference internally without copying. This is to
* minimize the number of extra copies introduced.
*/
- private LockscreenCredential(int type, int quality, byte[] credential) {
+ private LockscreenCredential(int type, byte[] credential) {
Preconditions.checkNotNull(credential);
if (type == CREDENTIAL_TYPE_NONE) {
Preconditions.checkArgument(credential.length == 0);
} else {
+ // Do not allow constructing a CREDENTIAL_TYPE_PASSWORD_OR_PIN object.
+ Preconditions.checkArgument(type == CREDENTIAL_TYPE_PIN
+ || type == CREDENTIAL_TYPE_PASSWORD
+ || type == CREDENTIAL_TYPE_PATTERN);
Preconditions.checkArgument(credential.length > 0);
}
mType = type;
- mQuality = quality;
mCredential = credential;
}
@@ -88,8 +85,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
* Creates a LockscreenCredential object representing empty password.
*/
public static LockscreenCredential createNone() {
- return new LockscreenCredential(CREDENTIAL_TYPE_NONE, PASSWORD_QUALITY_UNSPECIFIED,
- new byte[0]);
+ return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0]);
}
/**
@@ -97,7 +93,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
*/
public static LockscreenCredential createPattern(@NonNull List<LockPatternView.Cell> pattern) {
return new LockscreenCredential(CREDENTIAL_TYPE_PATTERN,
- PASSWORD_QUALITY_SOMETHING,
LockPatternUtils.patternToByteArray(pattern));
}
@@ -106,16 +101,25 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
*/
public static LockscreenCredential createPassword(@NonNull CharSequence password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
- PASSWORD_QUALITY_ALPHABETIC,
charSequenceToByteArray(password));
}
/**
+ * Creates a LockscreenCredential object representing a managed password for profile with
+ * unified challenge. This credentiall will have type {@code CREDENTIAL_TYPE_PASSWORD} for now.
+ * TODO: consider add a new credential type for this. This can then supersede the
+ * isLockTiedToParent argument in various places in LSS.
+ */
+ public static LockscreenCredential createManagedPassword(@NonNull byte[] password) {
+ return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
+ Arrays.copyOf(password, password.length));
+ }
+
+ /**
* Creates a LockscreenCredential object representing the given numeric PIN.
*/
public static LockscreenCredential createPin(@NonNull CharSequence pin) {
- return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
- PASSWORD_QUALITY_NUMERIC,
+ return new LockscreenCredential(CREDENTIAL_TYPE_PIN,
charSequenceToByteArray(pin));
}
@@ -143,27 +147,13 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
}
- /**
- * Create a LockscreenCredential object based on raw credential and type
- * TODO: Remove once LSS.setUserPasswordMetrics accepts a LockscreenCredential
- */
- public static LockscreenCredential createRaw(int type, byte[] credential) {
- if (type == CREDENTIAL_TYPE_NONE) {
- return createNone();
- } else {
- return new LockscreenCredential(type, PASSWORD_QUALITY_UNSPECIFIED, credential);
- }
- }
-
private void ensureNotZeroized() {
Preconditions.checkState(mCredential != null, "Credential is already zeroized");
}
/**
* Returns the type of this credential. Can be one of {@link #CREDENTIAL_TYPE_NONE},
- * {@link #CREDENTIAL_TYPE_PATTERN} or {@link #CREDENTIAL_TYPE_PASSWORD}.
- *
- * TODO: Remove once credential type is internal. Callers should use {@link #isNone},
- * {@link #isPattern} and {@link #isPassword} instead.
+ * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} or
+ * {@link #CREDENTIAL_TYPE_PASSWORD}.
*/
public int getType() {
ensureNotZeroized();
@@ -171,14 +161,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
/**
- * Returns the quality type of the credential
- */
- public int getQuality() {
- ensureNotZeroized();
- return mQuality;
- }
-
- /**
* Returns the credential bytes. This is a direct reference of the internal field so
* callers should not modify it.
*
@@ -200,9 +182,11 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
if (isPattern()) {
return StorageManager.CRYPT_TYPE_PATTERN;
}
+ if (isPin()) {
+ return StorageManager.CRYPT_TYPE_PIN;
+ }
if (isPassword()) {
- return mQuality == PASSWORD_QUALITY_NUMERIC
- ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD;
+ return StorageManager.CRYPT_TYPE_PASSWORD;
}
throw new IllegalStateException("Unhandled credential type");
}
@@ -219,7 +203,13 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
return mType == CREDENTIAL_TYPE_PATTERN;
}
- /** Returns whether this is a password credential */
+ /** Returns whether this is a numeric pin credential */
+ public boolean isPin() {
+ ensureNotZeroized();
+ return mType == CREDENTIAL_TYPE_PIN;
+ }
+
+ /** Returns whether this is an alphabetic password credential */
public boolean isPassword() {
ensureNotZeroized();
return mType == CREDENTIAL_TYPE_PASSWORD;
@@ -233,7 +223,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
/** Create a copy of the credential */
public LockscreenCredential duplicate() {
- return new LockscreenCredential(mType, mQuality,
+ return new LockscreenCredential(mType,
mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null);
}
@@ -263,7 +253,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
return;
}
- if (isPassword()) {
+ if (isPassword() || isPin()) {
if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must not be null and at least "
+ "of length " + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
@@ -272,10 +262,22 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
}
+ /**
+ * Check if this credential's type matches one that's retrieved from disk. The nuance here is
+ * that the framework used to not distinguish between PIN and password, so this method will
+ * allow a PIN/Password LockscreenCredential to match against the legacy
+ * {@link #CREDENTIAL_TYPE_PASSWORD_OR_PIN} stored on disk.
+ */
+ public boolean checkAgainstStoredType(int storedCredentialType) {
+ if (storedCredentialType == CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
+ return getType() == CREDENTIAL_TYPE_PASSWORD || getType() == CREDENTIAL_TYPE_PIN;
+ }
+ return getType() == storedCredentialType;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeInt(mQuality);
dest.writeByteArray(mCredential);
}
@@ -284,8 +286,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
@Override
public LockscreenCredential createFromParcel(Parcel source) {
- return new LockscreenCredential(source.readInt(), source.readInt(),
- source.createByteArray());
+ return new LockscreenCredential(source.readInt(), source.createByteArray());
}
@Override
@@ -307,7 +308,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
@Override
public int hashCode() {
// Effective Java — Item 9
- return ((17 + mType) * 31 + mQuality) * 31 + mCredential.hashCode();
+ return (17 + mType) * 31 + mCredential.hashCode();
}
@Override
@@ -315,8 +316,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
if (o == this) return true;
if (!(o instanceof LockscreenCredential)) return false;
final LockscreenCredential other = (LockscreenCredential) o;
- return mType == other.mType && mQuality == other.mQuality
- && Arrays.equals(mCredential, other.mCredential);
+ return mType == other.mType && Arrays.equals(mCredential, other.mCredential);
}
/**
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index ea0389f49a45..b7523963ec19 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -26,6 +26,7 @@ import android.os.Build;
import android.os.Environment;
import android.os.Process;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
import android.text.TextUtils;
@@ -33,6 +34,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimingsTraceLog;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -411,7 +413,13 @@ public class SystemConfig {
}
SystemConfig() {
- readAllPermissions();
+ TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ log.traceBegin("readAllPermissions");
+ try {
+ readAllPermissions();
+ } finally {
+ log.traceEnd();
+ }
}
private void readAllPermissions() {
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a568c13d7dde..f7d4b3f47edf 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -853,6 +853,7 @@ message GlobalSettingsProto {
optional SettingProto low_battery_sounds_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto trusted = 13;
optional SettingProto unlock = 14;
+ optional SettingProto wireless_charging_started = 15;
}
optional Sounds sounds = 110;
diff --git a/core/proto/android/server/notificationhistory.proto b/core/proto/android/server/notificationhistory.proto
new file mode 100644
index 000000000000..148bd7e4b663
--- /dev/null
+++ b/core/proto/android/server/notificationhistory.proto
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package com.android.server.notification;
+
+import "frameworks/base/core/proto/android/server/enums.proto";
+
+option java_multiple_files = true;
+
+// On disk data store for historical notifications
+message NotificationHistoryProto {
+ message StringPool {
+ optional int32 size = 1;
+ repeated string strings = 2;
+ }
+
+ message Notification {
+ // The package that posted the notification
+ optional string package = 1;
+ // package_index contains the index + 1 of the package name in the string pool
+ optional int32 package_index = 2;
+
+ // The name of the NotificationChannel this notification was posted to
+ optional string channel_name = 3;
+ // channel_name_index contains the index + 1 of the channel name in the string pool
+ optional int32 channel_name_index = 4;
+
+ // The id of the NotificationChannel this notification was posted to
+ optional string channel_id = 5;
+ // channel_id_index contains the index + 1 of the channel id in the string pool
+ optional int32 channel_id_index = 6;
+
+ // The uid of the package that posted the notification
+ optional int32 uid = 7;
+ // The user id of the package that posted the notification
+ optional int32 user_id = 8;
+ // The time at which the notification was posted
+ optional int64 posted_time_ms = 9;
+ // The title of the notification
+ optional string title = 10;
+ // The text of the notification
+ optional string text = 11;
+ // The small icon of the notification
+ optional Icon icon = 12;
+
+ // Matches the constants of android.graphics.drawable.Icon
+ enum ImageTypeEnum {
+ TYPE_UNKNOWN = 0;
+ TYPE_BITMAP = 1;
+ TYPE_RESOURCE = 2;
+ TYPE_DATA = 3;
+ TYPE_URI = 4;
+ TYPE_ADAPTIVE_BITMAP = 5;
+ }
+
+ message Icon {
+ optional ImageTypeEnum image_type = 1;
+ optional string image_bitmap_filename = 2;
+ optional int32 image_resource_id = 3;
+ optional bytes image_data = 4;
+ optional string image_uri = 5;
+ }
+ }
+
+ // The time the last entry was written
+ optional int64 end_time_ms = 1;
+ // Pool of strings to save space
+ optional StringPool stringpool = 2;
+ // Versioning fields
+ optional int32 major_version = 3;
+ optional int32 minor_version = 4;
+
+ // List of historical notifications
+ repeated Notification notification = 5;
+}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 75cdb42ddccc..eaf93eb9e216 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4357,4 +4357,8 @@
create additional screen real estate outside beyond the keyboard. Note that the user needs
to have a confirmed way to dismiss the keyboard when desired. -->
<bool name="config_automotiveHideNavBarForKeyboard">false</bool>
+
+ <!-- Whether or not to show the built-in charging animation when the device begins charging
+ wirelessly. -->
+ <bool name="config_showBuiltinWirelessChargingAnim">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a01bbe38f296..9791241a52af 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -41,6 +41,8 @@
<dimen name="quick_qs_offset_height">48dp</dimen>
<!-- Total height of QQS (quick_qs_offset_height + 128) -->
<dimen name="quick_qs_total_height">176dp</dimen>
+ <!-- Total height of QQS with two rows to fit media player (quick_qs_offset_height + 176) -->
+ <dimen name="quick_qs_total_height_with_media">224dp</dimen>
<!-- Height of the bottom navigation / system bar. -->
<dimen name="navigation_bar_height">48dp</dimen>
<!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf5f706b1234..d88178d481e9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5205,6 +5205,8 @@
<string name="autofill_save_no">No thanks</string>
<!-- Label for the autofill update button [CHAR LIMIT=NONE] -->
<string name="autofill_update_yes">Update</string>
+ <!-- Label for the autofill continue button [CHAR LIMIT=NONE] -->
+ <string name="autofill_continue_yes">Continue</string>
<!-- Label for the type of data being saved for autofill when it represent user credentials with a password [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_password">password</string>
@@ -5212,6 +5214,12 @@
<string name="autofill_save_type_address">address</string>
<!-- Label for the type of data being saved for autofill when it represents a credit card [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_credit_card">credit card</string>
+ <!-- Label for the type of data being saved for autofill when it represents a debit card [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_debit_card">debit card</string>
+ <!-- Label for the type of data being saved for autofill when it represents a payment card [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_payment_card">payment card</string>
+ <!-- Label for the type of data being saved for autofill when it represents a card that does not a specified type or cannot identify what the type is for [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_type_generic_card">card</string>
<!-- Label for the type of data being saved for autofill when it represents an username [CHAR LIMIT=NONE] -->
<string name="autofill_save_type_username">username</string>
<!-- Label for the type of data being saved for autofill when it represents an email address [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6bb471978645..e2f57fda5bc5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1774,6 +1774,7 @@
<java-symbol type="dimen" name="display_cutout_touchable_region_size" />
<java-symbol type="dimen" name="quick_qs_offset_height" />
<java-symbol type="dimen" name="quick_qs_total_height" />
+ <java-symbol type="dimen" name="quick_qs_total_height_with_media" />
<java-symbol type="drawable" name="ic_jog_dial_sound_off" />
<java-symbol type="drawable" name="ic_jog_dial_sound_on" />
<java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -3355,6 +3356,7 @@
<java-symbol type="string" name="autofill_update_title_with_2types" />
<java-symbol type="string" name="autofill_update_title_with_3types" />
<java-symbol type="string" name="autofill_update_yes" />
+ <java-symbol type="string" name="autofill_continue_yes" />
<java-symbol type="string" name="autofill_save_accessibility_title " />
<java-symbol type="string" name="autofill_save_title" />
<java-symbol type="string" name="autofill_save_title_with_type" />
@@ -3365,6 +3367,9 @@
<java-symbol type="string" name="autofill_save_type_password" />
<java-symbol type="string" name="autofill_save_type_address" />
<java-symbol type="string" name="autofill_save_type_credit_card" />
+ <java-symbol type="string" name="autofill_save_type_debit_card" />
+ <java-symbol type="string" name="autofill_save_type_payment_card" />
+ <java-symbol type="string" name="autofill_save_type_generic_card" />
<java-symbol type="string" name="autofill_save_type_username" />
<java-symbol type="string" name="autofill_save_type_email_address" />
<java-symbol type="drawable" name="autofill_dataset_picker_background" />
@@ -3866,4 +3871,6 @@
<java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
+ <java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
+
</resources>
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
index 5eec91c8840b..05bab1c185de 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
@@ -31,10 +31,23 @@ public class LockscreenCredentialTest extends AndroidTestCase {
assertEquals(0, empty.size());
assertNotNull(empty.getCredential());
+ assertFalse(empty.isPin());
assertFalse(empty.isPassword());
assertFalse(empty.isPattern());
}
+ public void testPinCredential() {
+ LockscreenCredential pin = LockscreenCredential.createPin("3456");
+
+ assertTrue(pin.isPin());
+ assertEquals(4, pin.size());
+ assertTrue(Arrays.equals("3456".getBytes(), pin.getCredential()));
+
+ assertFalse(pin.isNone());
+ assertFalse(pin.isPassword());
+ assertFalse(pin.isPattern());
+ }
+
public void testPasswordCredential() {
LockscreenCredential password = LockscreenCredential.createPassword("password");
@@ -43,6 +56,7 @@ public class LockscreenCredentialTest extends AndroidTestCase {
assertTrue(Arrays.equals("password".getBytes(), password.getCredential()));
assertFalse(password.isNone());
+ assertFalse(password.isPin());
assertFalse(password.isPattern());
}
@@ -60,6 +74,7 @@ public class LockscreenCredentialTest extends AndroidTestCase {
assertTrue(Arrays.equals("12369".getBytes(), pattern.getCredential()));
assertFalse(pattern.isNone());
+ assertFalse(pattern.isPin());
assertFalse(pattern.isPassword());
}
@@ -72,6 +87,15 @@ public class LockscreenCredentialTest extends AndroidTestCase {
LockscreenCredential.createPasswordOrNone("abcd"));
}
+ public void testPinOrNoneCredential() {
+ assertEquals(LockscreenCredential.createNone(),
+ LockscreenCredential.createPinOrNone(null));
+ assertEquals(LockscreenCredential.createNone(),
+ LockscreenCredential.createPinOrNone(""));
+ assertEquals(LockscreenCredential.createPin("1357"),
+ LockscreenCredential.createPinOrNone("1357"));
+ }
+
public void testSanitize() {
LockscreenCredential password = LockscreenCredential.createPassword("password");
password.zeroize();
@@ -80,12 +104,15 @@ public class LockscreenCredentialTest extends AndroidTestCase {
password.isNone();
fail("Sanitized credential still accessible");
} catch (IllegalStateException expected) { }
-
try {
password.isPattern();
fail("Sanitized credential still accessible");
} catch (IllegalStateException expected) { }
try {
+ password.isPin();
+ fail("Sanitized credential still accessible");
+ } catch (IllegalStateException expected) { }
+ try {
password.isPassword();
fail("Sanitized credential still accessible");
} catch (IllegalStateException expected) { }
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index 9913531cdf13..50e8474e8d52 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -62,7 +62,9 @@ public class LockPatternUtilsTest {
Settings.Global.putInt(cr, Settings.Global.DEVICE_DEMO_MODE, deviceDemoMode);
final ILockSettings ils = Mockito.mock(ILockSettings.class);
- when(ils.havePassword(DEMO_USER_ID)).thenReturn(isSecure);
+ when(ils.getCredentialType(DEMO_USER_ID)).thenReturn(
+ isSecure ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
+ : LockPatternUtils.CREDENTIAL_TYPE_NONE);
when(ils.getLong("lockscreen.password_type", PASSWORD_QUALITY_UNSPECIFIED, DEMO_USER_ID))
.thenReturn((long) PASSWORD_QUALITY_MANAGED);
// TODO(b/63758238): stop spying the class under test
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 8a76d6b3fc7a..6e3e43af8c6f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -242,7 +242,8 @@ private:
nsecs_t queueDuration;
};
- RingBuffer<SwapHistory, 3> mSwapHistory;
+ // Need at least 4 because we do quad buffer. Add a 5th for good measure.
+ RingBuffer<SwapHistory, 5> mSwapHistory;
int64_t mFrameNumber = -1;
// last vsync for a dropped frame due to stuffed queue
diff --git a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
index c022388e0aa8..347e4e8ebe4b 100644
--- a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
+++ b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
@@ -33,9 +33,10 @@ interface IPlatformCompatNative
* 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 userId The ID of the user that the operation is done for.
* @param packageName The package name of the app in question.
*/
- void reportChangeByPackageName(long changeId, @utf8InCpp String packageName);
+ void reportChangeByPackageName(long changeId, @utf8InCpp String packageName, int userId);
/**
* Reports that a compatibility change is affecting an app process now.
@@ -64,9 +65,10 @@ interface IPlatformCompatNative
*
* @param changeId The ID of the compatibility change in question.
* @param packageName The package name of the app in question.
+ * @param userId The ID of the user that the operation is done for.
* @return {@code true} if the change is enabled for the current app.
*/
- boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName);
+ boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName, int userId);
/**
* Query if a given compatibility change is enabled for an app process. This method should
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 53c01226ca1a..b34b31ac8439 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -294,7 +294,7 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction,
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto& [surfaceControl, acquireTime, previousReleaseFence] : surfaceControlStats) {
+ for (const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 011d5ea9d86b..be4b8897d00b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,6 +20,7 @@ import android.content.Context;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.navigationbar.car.CarFacetButtonController;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index b1067f8c3df5..0f44e0815a86 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -23,6 +23,7 @@ import android.content.Context;
import com.android.systemui.car.CarNotificationEntryManager;
import com.android.systemui.car.CarNotificationInterruptionStateProvider;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.power.EnhancedEstimates;
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
index 325c98890b11..c2847c88785b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
@@ -16,6 +16,12 @@
package com.android.systemui;
+import com.android.systemui.dagger.DependencyBinder;
+import com.android.systemui.dagger.DependencyProvider;
+import com.android.systemui.dagger.SystemServicesModule;
+import com.android.systemui.dagger.SystemUIModule;
+import com.android.systemui.dagger.SystemUIRootComponent;
+
import javax.inject.Singleton;
import dagger.Component;
@@ -26,6 +32,7 @@ import dagger.Component;
DependencyProvider.class,
DependencyBinder.class,
SystemUIFactory.ContextHolder.class,
+ SystemServicesModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
CarSystemUIBinder.class
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 5bb35309edd2..6fba1d516c73 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -16,8 +16,6 @@
package com.android.systemui.navigationbar.car;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.content.Context;
import android.graphics.PixelFormat;
import android.inputmethodservice.InputMethodService;
@@ -35,6 +33,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NavigationBarController;
@@ -47,7 +46,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import javax.inject.Inject;
-import javax.inject.Named;
import dagger.Lazy;
@@ -96,7 +94,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager windowManager,
DeviceProvisionedController deviceProvisionedController,
Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler,
+ @MainHandler Handler mainHandler,
Lazy<KeyguardStateController> keyguardStateController,
Lazy<CarFacetButtonController> facetButtonController,
Lazy<NavigationBarController> navigationBarController,
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java
index 128721eede2b..519b33a2f53e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/NavigationBarViewFactory.java
@@ -108,7 +108,7 @@ public class NavigationBarViewFactory {
private ViewGroup getWindowCached(Type type) {
if (mCachedContainerMap.containsKey(type)) {
- return mCachedViewMap.get(type);
+ return mCachedContainerMap.get(type);
}
ViewGroup window = (ViewGroup) View.inflate(mContext,
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 3424eeaeb854..cd81a5cb5c4f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -161,9 +161,18 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private Drawable mNotificationPanelBackground;
private ViewGroup mTopNavigationBarContainer;
+ private ViewGroup mNavigationBarWindow;
+ private ViewGroup mLeftNavigationBarWindow;
+ private ViewGroup mRightNavigationBarWindow;
private CarNavigationBarView mTopNavigationBarView;
+ private CarNavigationBarView mNavigationBarView;
+ private CarNavigationBarView mLeftNavigationBarView;
+ private CarNavigationBarView mRightNavigationBarView;
private final Object mQueueLock = new Object();
+ private boolean mShowLeft;
+ private boolean mShowRight;
+ private boolean mShowBottom;
private final NavigationBarViewFactory mNavigationBarViewFactory;
private CarFacetButtonController mCarFacetButtonController;
private DeviceProvisionedController mDeviceProvisionedController;
@@ -429,6 +438,16 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mHvacController.removeAllComponents();
mCarFacetButtonController.removeAll();
+ if (mNavigationBarWindow != null) {
+ mNavigationBarView = null;
+ }
+ if (mLeftNavigationBarWindow != null) {
+ mLeftNavigationBarView = null;
+ }
+ if (mRightNavigationBarWindow != null) {
+ mRightNavigationBarView = null;
+ }
+
buildNavBarContent();
// CarFacetButtonController was reset therefore we need to re-add the status bar elements
// to the controller.
@@ -451,28 +470,28 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
* the full screen user selector is shown.
*/
void setNavBarVisibility(@View.Visibility int visibility) {
- if (mNavigationBarViewFactory.getBottomWindow() != null) {
- mNavigationBarViewFactory.getBottomWindow().setVisibility(visibility);
+ if (mNavigationBarWindow != null) {
+ mNavigationBarWindow.setVisibility(visibility);
}
- if (mNavigationBarViewFactory.getLeftWindow() != null) {
- mNavigationBarViewFactory.getLeftWindow().setVisibility(visibility);
+ if (mLeftNavigationBarWindow != null) {
+ mLeftNavigationBarWindow.setVisibility(visibility);
}
- if (mNavigationBarViewFactory.getRightWindow() != null) {
- mNavigationBarViewFactory.getRightWindow().setVisibility(visibility);
+ if (mRightNavigationBarWindow != null) {
+ mRightNavigationBarWindow.setVisibility(visibility);
}
}
@Override
public boolean hideKeyguard() {
boolean result = super.hideKeyguard();
- if (mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser).hideKeyguardButtons();
+ if (mNavigationBarView != null) {
+ mNavigationBarView.hideKeyguardButtons();
}
- if (mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser).hideKeyguardButtons();
+ if (mLeftNavigationBarView != null) {
+ mLeftNavigationBarView.hideKeyguardButtons();
}
- if (mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser).hideKeyguardButtons();
+ if (mRightNavigationBarView != null) {
+ mRightNavigationBarView.hideKeyguardButtons();
}
return result;
}
@@ -487,14 +506,14 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
* Switch to the keyguard applicable content contained in the nav bars
*/
private void updateNavBarForKeyguardContent() {
- if (mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser).showKeyguardButtons();
+ if (mNavigationBarView != null) {
+ mNavigationBarView.showKeyguardButtons();
}
- if (mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser).showKeyguardButtons();
+ if (mLeftNavigationBarView != null) {
+ mLeftNavigationBarView.showKeyguardButtons();
}
- if (mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser).showKeyguardButtons();
+ if (mRightNavigationBarView != null) {
+ mRightNavigationBarView.showKeyguardButtons();
}
}
@@ -599,26 +618,19 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
mNotificationDataManager = new NotificationDataManager();
mNotificationDataManager.setOnUnseenCountUpdateListener(
() -> {
- if (mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser) != null
- && mNotificationDataManager != null) {
+ if (mNavigationBarView != null && mNotificationDataManager != null) {
Boolean hasUnseen =
mNotificationDataManager.getUnseenNotificationCount() > 0;
- if (mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getBottomBar(
- mDeviceIsSetUpForUser).toggleNotificationUnseenIndicator(
- hasUnseen);
+ if (mNavigationBarView != null) {
+ mNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
}
- if (mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getLeftBar(
- mDeviceIsSetUpForUser).toggleNotificationUnseenIndicator(
- hasUnseen);
+ if (mLeftNavigationBarView != null) {
+ mLeftNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
}
- if (mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser) != null) {
- mNavigationBarViewFactory.getRightBar(
- mDeviceIsSetUpForUser).toggleNotificationUnseenIndicator(
- hasUnseen);
+ if (mRightNavigationBarView != null) {
+ mRightNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
}
}
});
@@ -873,6 +885,10 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
@Override
protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
+ mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
+ mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
+ mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+
buildNavBarWindows();
buildNavBarContent();
}
@@ -880,22 +896,40 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt
private void buildNavBarContent() {
buildTopBar();
- CarNavigationBarView bottom = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser);
- bottom.setStatusBar(this);
- bottom.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener);
+ if (mShowBottom) {
+ mNavigationBarView = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser);
+ mNavigationBarView.setStatusBar(this);
+ mNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener);
+ }
- CarNavigationBarView left = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
- left.setStatusBar(this);
- left.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener);
+ if (mShowLeft) {
+ mLeftNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
+ mLeftNavigationBarView.setStatusBar(this);
+ mLeftNavigationBarView.setStatusBarWindowTouchListener(
+ mNavBarNotificationTouchListener);
+ }
- CarNavigationBarView right = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
- right.setStatusBar(this);
- right.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener);
+ if (mShowRight) {
+ mRightNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
+ mRightNavigationBarView.setStatusBar(this);
+ mRightNavigationBarView.setStatusBarWindowTouchListener(
+ mNavBarNotificationTouchListener);
+ }
}
private void buildNavBarWindows() {
mTopNavigationBarContainer = mStatusBarWindow
.findViewById(R.id.car_top_navigation_bar_container);
+
+ if (mShowBottom) {
+ mNavigationBarWindow = mNavigationBarViewFactory.getBottomWindow();
+ }
+ if (mShowLeft) {
+ mLeftNavigationBarWindow = mNavigationBarViewFactory.getLeftWindow();
+ }
+ if (mShowRight) {
+ mRightNavigationBarWindow = mNavigationBarViewFactory.getRightWindow();
+ }
}
private void buildTopBar() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 4e6c005457c0..658a0b59622c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -93,6 +93,7 @@ public class WifiUtils {
if (bssid != null) {
visibility.append(" ").append(bssid);
}
+ visibility.append(" technology = ").append(info.getWifiTechnology());
visibility.append(" rssi=").append(info.getRssi());
visibility.append(" ");
visibility.append(" score=").append(info.score);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 17c621e6fbef..44de09b8d21d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1497,21 +1497,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
if (upgradeVersion == 94) {
- // Add wireless charging started sound setting
- if (mUserHandle == UserHandle.USER_SYSTEM) {
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
- + " VALUES(?,?);");
- loadStringSetting(stmt, Settings.Global.CHARGING_STARTED_SOUND,
- R.string.def_wireless_charging_started_sound);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
- }
+ // charging sound moved to SettingsProvider version 184
upgradeVersion = 95;
}
@@ -2562,8 +2548,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
R.string.def_car_dock_sound);
loadStringSetting(stmt, Settings.Global.CAR_UNDOCK_SOUND,
R.string.def_car_undock_sound);
- loadStringSetting(stmt, Settings.Global.CHARGING_STARTED_SOUND,
- R.string.def_wireless_charging_started_sound);
loadIntegerSetting(stmt, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
R.integer.def_dock_audio_media_enabled);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6bd26bf03a55..e24d387c5649 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1347,6 +1347,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.CHARGING_STARTED_SOUND,
GlobalSettingsProto.Sounds.CHARGING_STARTED);
+ dumpSetting(s, p,
+ Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+ GlobalSettingsProto.Sounds.WIRELESS_CHARGING_STARTED);
p.end(soundsToken);
final long soundTriggerToken = p.start(GlobalSettingsProto.SOUND_TRIGGER);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 06398640acb4..80faf4766e36 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3206,7 +3206,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 183;
+ private static final int SETTINGS_VERSION = 184;
private final int mUserId;
@@ -3845,23 +3845,7 @@ public class SettingsProvider extends ContentProvider {
}
if (currentVersion == 155) {
- // Version 156: Set the default value for CHARGING_STARTED_SOUND.
- final SettingsState globalSettings = getGlobalSettingsLocked();
- final String oldValue = globalSettings.getSettingLocked(
- Global.CHARGING_STARTED_SOUND).getValue();
- final String oldDefault = getContext().getResources().getString(
- R.string.def_wireless_charging_started_sound);
- if (TextUtils.equals(null, oldValue)
- || TextUtils.equals(oldValue, oldDefault)) {
- final String defaultValue = getContext().getResources().getString(
- R.string.def_charging_started_sound);
- if (!TextUtils.isEmpty(defaultValue)) {
- globalSettings.insertSettingLocked(
- Settings.Global.CHARGING_STARTED_SOUND, defaultValue,
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
- }
-
- }
+ // Version 156: migrated to version 184
currentVersion = 156;
}
@@ -4416,6 +4400,48 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 183;
}
+ if (currentVersion == 183) {
+ // Version 184: Set default values for WIRELESS_CHARGING_STARTED_SOUND
+ // and CHARGING_STARTED_SOUND
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+
+ final String oldValueWireless = globalSettings.getSettingLocked(
+ Global.WIRELESS_CHARGING_STARTED_SOUND).getValue();
+ final String oldValueWired = globalSettings.getSettingLocked(
+ Global.CHARGING_STARTED_SOUND).getValue();
+
+ final String defaultValueWireless = getContext().getResources().getString(
+ R.string.def_wireless_charging_started_sound);
+ final String defaultValueWired = getContext().getResources().getString(
+ R.string.def_charging_started_sound);
+
+ // wireless charging sound
+ if (oldValueWireless == null
+ || TextUtils.equals(oldValueWireless, defaultValueWired)) {
+ if (!TextUtils.isEmpty(defaultValueWireless)) {
+ globalSettings.insertSettingLocked(
+ Global.WIRELESS_CHARGING_STARTED_SOUND, defaultValueWireless,
+ null /* tag */, true /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ } else if (!TextUtils.isEmpty(defaultValueWired)) {
+ // if the wireless sound is empty, use the wired charging sound
+ globalSettings.insertSettingLocked(
+ Global.WIRELESS_CHARGING_STARTED_SOUND, defaultValueWired,
+ null /* tag */, true /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+
+ // wired charging sound
+ if (oldValueWired == null && !TextUtils.isEmpty(defaultValueWired)) {
+ globalSettings.insertSettingLocked(
+ Global.CHARGING_STARTED_SOUND, defaultValueWired,
+ null /* tag */, true /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 184;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 62827bc3a98e..179ba8ad086a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -559,6 +559,7 @@ public class SettingsBackupTest {
Settings.Global.WIFI_WATCHDOG_ON,
Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
Settings.Global.CHARGING_STARTED_SOUND,
+ Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
Settings.Global.WINDOW_ANIMATION_SCALE,
Settings.Global.WTF_IS_FATAL,
Settings.Global.ZEN_MODE,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e11c063f57fb..54e291f904eb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -247,23 +247,6 @@
android:exported="false" />
<receiver
- android:name=".BugreportReceiver"
- android:permission="android.permission.DUMP">
- <intent-filter>
- <action android:name="com.android.internal.intent.action.BUGREPORT_STARTED" />
- <action android:name="com.android.internal.intent.action.BUGREPORT_FINISHED" />
- </intent-filter>
- </receiver>
-
- <receiver
- android:name=".RemoteBugreportReceiver"
- android:permission="android.permission.DUMP">
- <intent-filter>
- <action android:name="com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED" />
- </intent-filter>
- </receiver>
-
- <receiver
android:name=".BugreportRequestedReceiver"
android:permission="android.permission.TRIGGER_SHELL_BUGREPORT">
<intent-filter>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 665bde341515..1b35770ccbd7 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -56,16 +56,11 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.IDumpstate;
-import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -80,7 +75,6 @@ import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.IWindowManager;
import android.view.View;
-import android.view.View.OnFocusChangeListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
@@ -122,31 +116,9 @@ import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
- * Service used to keep progress of bugreport processes ({@code dumpstate} and
- * {@code BugreportManager}).
+ * Service used to trigger system bugreports.
* <p>
- * There can be 2 workflows. One workflow via ({@code dumpstate}) is:
- * <ol>
- * <li>When {@code dumpstate} starts, it sends a {@code BUGREPORT_STARTED} with a sequential id,
- * its pid, and the estimated total effort.
- * <li>{@link BugreportReceiver} receives the intent and delegates it to this service.
- * <li>Upon start, this service:
- * <ol>
- * <li>Issues a system notification so user can watch the progress (which is 0% initially).
- * <li>Polls the {@link SystemProperties} for updates on the {@code dumpstate} progress.
- * <li>If the progress changed, it updates the system notification.
- * </ol>
- * <li>As {@code dumpstate} progresses, it updates the system property.
- * <li>When {@code dumpstate} finishes, it sends a {@code BUGREPORT_FINISHED} intent.
- * <li>{@link BugreportReceiver} receives the intent and delegates it to this service, which in
- * turn:
- * <ol>
- * <li>Updates the system notification so user can share the bugreport.
- * <li>Stops monitoring that {@code dumpstate} process.
- * <li>Stops itself if it doesn't have any process left to monitor.
- * </ol>
- * </ol>
- * The second workflow using Bugreport API({@code BugreportManager}) is:
+ * The workflow uses Bugreport API({@code BugreportManager}) and is as follows:
* <ol>
* <li>System apps like Settings or SysUI broadcasts {@code BUGREPORT_REQUESTED}.
* <li>{@link BugreportRequestedReceiver} receives the intent and delegates it to this service.
@@ -164,18 +136,14 @@ public class BugreportProgressService extends Service {
private static final String AUTHORITY = "com.android.shell";
- // External intents sent by dumpstate.
- static final String INTENT_BUGREPORT_STARTED =
- "com.android.internal.intent.action.BUGREPORT_STARTED";
- static final String INTENT_BUGREPORT_FINISHED =
- "com.android.internal.intent.action.BUGREPORT_FINISHED";
- static final String INTENT_REMOTE_BUGREPORT_FINISHED =
- "com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED";
-
// External intent used to trigger bugreport API.
static final String INTENT_BUGREPORT_REQUESTED =
"com.android.internal.intent.action.BUGREPORT_REQUESTED";
+ // Intent sent to notify external apps that bugreport finished
+ static final String INTENT_BUGREPORT_FINISHED =
+ "com.android.internal.intent.action.BUGREPORT_FINISHED";
+
// Internal intents used on notification actions.
static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
@@ -188,7 +156,6 @@ public class BugreportProgressService extends Service {
static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
static final String EXTRA_ID = "android.intent.extra.ID";
- static final String EXTRA_PID = "android.intent.extra.PID";
static final String EXTRA_MAX = "android.intent.extra.MAX";
static final String EXTRA_NAME = "android.intent.extra.NAME";
static final String EXTRA_TITLE = "android.intent.extra.TITLE";
@@ -218,15 +185,9 @@ public class BugreportProgressService extends Service {
*/
static final int SCREENSHOT_DELAY_SECONDS = 3;
- // TODO: will be gone once fully migrated to Binder
- /** System properties used to communicate with dumpstate progress. */
- private static final String DUMPSTATE_PREFIX = "dumpstate.";
- private static final String NAME_SUFFIX = ".name";
+ /** System property where dumpstate stores last triggered bugreport id */
private static final String PROPERTY_LAST_ID = "dumpstate.last_id";
- /** System property (and value) used to stop dumpstate. */
- // TODO: should call ActiveManager API instead
- private static final String CTL_STOP = "ctl.stop";
private static final String BUGREPORT_SERVICE = "bugreport";
/**
@@ -273,8 +234,6 @@ public class BugreportProgressService extends Service {
private File mScreenshotsDir;
- private boolean mUsingBugreportApi;
-
private BugreportManager mBugreportManager;
/**
@@ -452,9 +411,9 @@ public class BugreportProgressService extends Service {
cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE);
final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
intent.putExtra(EXTRA_BUGREPORT, bugreportFilePath);
- addScreenshotToIntent(intent, mInfo);
+ intent.putExtra(EXTRA_SCREENSHOT, getScreenshotForIntent(mInfo));
mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
- onBugreportFinished(mInfo.id);
+ onBugreportFinished(mInfo);
}
}
}
@@ -475,14 +434,17 @@ public class BugreportProgressService extends Service {
android.Manifest.permission.DUMP);
}
- private static void addScreenshotToIntent(Intent intent, BugreportInfo info) {
- final File screenshotFile = info.screenshotFiles.isEmpty()
- ? null : info.screenshotFiles.get(0);
- if (screenshotFile != null && screenshotFile.length() > 0) {
+ /**
+ * Checks if screenshot array is non-empty and returns the first screenshot's path. The first
+ * screenshot is the default screenshot for the bugreport types that take it.
+ */
+ private static String getScreenshotForIntent(BugreportInfo info) {
+ if (!info.screenshotFiles.isEmpty()) {
+ final File screenshotFile = info.screenshotFiles.get(0);
final String screenshotFilePath = screenshotFile.getAbsolutePath();
- intent.putExtra(EXTRA_SCREENSHOT, screenshotFilePath);
+ return screenshotFilePath;
}
- return;
+ return null;
}
private static String generateFileHash(String fileName) {
@@ -558,40 +520,24 @@ public class BugreportProgressService extends Service {
Log.v(TAG, "handleMessage(): " + dumpIntent((Intent) parcel));
final Intent intent;
if (parcel instanceof Intent) {
- // The real intent was passed to BugreportReceiver, which delegated to the service.
+ // The real intent was passed to BugreportRequestedReceiver,
+ // which delegated to the service.
intent = (Intent) parcel;
} else {
intent = (Intent) msg.obj;
}
final String action = intent.getAction();
- final int pid = intent.getIntExtra(EXTRA_PID, 0);
final int id = intent.getIntExtra(EXTRA_ID, 0);
final int max = intent.getIntExtra(EXTRA_MAX, -1);
final String name = intent.getStringExtra(EXTRA_NAME);
if (DEBUG)
- Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id + ", pid: "
- + pid + ", max: " + max);
+ Log.v(TAG, "action: " + action + ", name: " + name + ", id: " + id
+ + ", max: " + max);
switch (action) {
case INTENT_BUGREPORT_REQUESTED:
startBugreportAPI(intent);
break;
- case INTENT_BUGREPORT_STARTED:
- if (!mUsingBugreportApi && !startProgress(name, id, pid, max)) {
- stopSelfWhenDone();
- return;
- }
- break;
- case INTENT_BUGREPORT_FINISHED:
- if (!mUsingBugreportApi) {
- if (id == 0) {
- // Shouldn't happen, unless BUGREPORT_FINISHED is received
- // from a legacy, out-of-sync dumpstate process.
- Log.w(TAG, "Missing " + EXTRA_ID + " on intent " + intent);
- }
- onBugreportFinished(id, intent);
- }
- break;
case INTENT_BUGREPORT_INFO_LAUNCH:
launchBugreportInfoDialog(id);
break;
@@ -633,52 +579,12 @@ public class BugreportProgressService extends Service {
private BugreportInfo getInfo(int id) {
final BugreportInfo bugreportInfo = mBugreportInfos.get(id);
if (bugreportInfo == null) {
- Log.w(TAG, "Not monitoring process with ID " + id);
+ Log.w(TAG, "Not monitoring bugreports with ID " + id);
return null;
}
return bugreportInfo;
}
- /**
- * Creates the {@link BugreportInfo} for a process and issue a system notification to
- * indicate its progress.
- *
- * @return whether it succeeded or not.
- */
- private boolean startProgress(String name, int id, int pid, int max) {
- if (name == null) {
- Log.w(TAG, "Missing " + EXTRA_NAME + " on start intent");
- }
- if (id == -1) {
- Log.e(TAG, "Missing " + EXTRA_ID + " on start intent");
- return false;
- }
- if (pid == -1) {
- Log.e(TAG, "Missing " + EXTRA_PID + " on start intent");
- return false;
- }
- if (max <= 0) {
- Log.e(TAG, "Invalid value for extra " + EXTRA_MAX + ": " + max);
- return false;
- }
-
- final BugreportInfo info = new BugreportInfo(mContext, id, pid, name, max);
- if (mBugreportInfos.indexOfKey(id) >= 0) {
- // BUGREPORT_STARTED intent was already received; ignore it.
- Log.w(TAG, "ID " + id + " already watched");
- return true;
- }
- final DumpstateListener listener = new DumpstateListener(info);
- mBugreportInfos.put(info.id, info);
- if (listener.connect()) {
- updateProgress(info);
- return true;
- } else {
- Log.w(TAG, "not updating progress because it could not connect to dumpstate");
- return false;
- }
- }
-
private String getBugreportBaseName(@BugreportParams.BugreportMode int type) {
String buildId = SystemProperties.get("ro.build.id", "UNKNOWN_BUILD");
String deviceName = SystemProperties.get("ro.product.name", "UNKNOWN_DEVICE");
@@ -694,7 +600,6 @@ public class BugreportProgressService extends Service {
}
private void startBugreportAPI(Intent intent) {
- mUsingBugreportApi = true;
String shareTitle = intent.getStringExtra(EXTRA_TITLE);
String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
@@ -702,10 +607,8 @@ public class BugreportProgressService extends Service {
String baseName = getBugreportBaseName(bugreportType);
String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
- // pid not used in this workflow, so setting default = 0
- BugreportInfo info = new BugreportInfo(mContext, 0 /* pid */, baseName, name,
- 100 /* max progress*/, shareTitle, shareDescription, bugreportType,
- mUsingBugreportApi);
+ BugreportInfo info = new BugreportInfo(mContext, baseName, name,
+ 100 /* max progress*/, shareTitle, shareDescription, bugreportType);
ParcelFileDescriptor bugreportFd = info.createBugreportFd();
if (bugreportFd == null) {
@@ -885,11 +788,7 @@ public class BugreportProgressService extends Service {
final BugreportInfo info = getInfo(id);
if (info != null && !info.finished) {
Log.i(TAG, "Cancelling bugreport service (ID=" + id + ") on user's request");
- if (mUsingBugreportApi) {
- mBugreportManager.cancelBugreport();
- } else {
- setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
- }
+ mBugreportManager.cancelBugreport();
deleteScreenshots(info);
}
synchronized (mLock) {
@@ -1087,94 +986,15 @@ public class BugreportProgressService extends Service {
}
/**
- * Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
- */
- private void onBugreportFinished(int id, Intent intent) {
- final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
- if (bugreportFile == null) {
- // Should never happen, dumpstate always set the file.
- Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
- return;
- }
- final int max = intent.getIntExtra(EXTRA_MAX, -1);
- final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
- final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
- final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
- onBugreportFinished(id, bugreportFile, screenshotFile, shareTitle, shareDescription, max);
- }
-
- /**
- * Handles the onfinish() call by BugreportCallbackImpl using the id
- */
- private void onBugreportFinished(int id) {
- BugreportInfo info = getInfo(id);
- final File bugreportFile = info.bugreportFile;
- final int max = -1; // this is to log metrics for dumpstate duration.
- File screenshotFile = info.screenshotFiles.isEmpty()
- ? null : info.screenshotFiles.get(0);
- // If the screenshot file did not get populated implies this type of bugreport does not
- // need the screenshot file; setting the file to null so that empty file doesnt get shared
- if (screenshotFile != null && screenshotFile.length() == 0) {
- if (screenshotFile.delete()) {
- Log.d(TAG, "screenshot file deleted successfully.");
- }
- info.screenshotFiles.remove(0);
- // TODO(b/136066578): Will soon stop using the below variable as it is a no-op in
- // API flow and the screenshotFile value is read from info.screenshotFiles
- screenshotFile = null;
- }
- // TODO: Since we are passing id to the function, it should be able to find the info linked
- // to the id and therefore use the value of shareTitle and shareDescription.
- onBugreportFinished(id, bugreportFile, screenshotFile, info.shareTitle,
- info.shareDescription, max);
- }
-
-
- /**
* Wraps up bugreport generation and triggers a notification to share the bugreport.
*/
- private void onBugreportFinished(int id, File bugreportFile, @Nullable File screenshotFile,
- String shareTitle, String shareDescription, int max) {
- mInfoDialog.onBugreportFinished();
- BugreportInfo info = getInfo(id);
- if (info == null) {
- // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
- Log.v(TAG, "Creating info for untracked ID " + id);
- info = new BugreportInfo(mContext, id);
- DumpstateListener dumpstateListener = new DumpstateListener(info);
- mBugreportInfos.put(id, info);
- }
- if (!mUsingBugreportApi) {
- // Rename in API flow happens before sending the broadcast for remote bugreport (to
- // handle renaming before sending broadcasts)
- info.renameScreenshots(mScreenshotsDir);
- // API workflow already has the bugreport file. This was required in legacy flow, when
- // FINISHED broadcast would send the final bugreport files.
- // TODO(b/136066578): Change function definition to not include bugreport/screenshot
- // file in params
- info.bugreportFile = bugreportFile;
- if (screenshotFile != null) {
- info.addScreenshot(screenshotFile);
- }
- }
-
- if (max != -1) {
- MetricsLogger.histogram(this, "dumpstate_duration", max);
- info.max = max;
- }
-
- if (!TextUtils.isEmpty(shareTitle)) {
- info.title = shareTitle;
- if (!TextUtils.isEmpty(shareDescription)) {
- info.shareDescription= shareDescription;
- }
- Log.d(TAG, "Bugreport title is " + info.title + ","
- + " shareDescription is " + info.shareDescription);
- }
+ private void onBugreportFinished(BugreportInfo info) {
+ Log.d(TAG, "Bugreport finished with title: " + info.title
+ + " and shareDescription: " + info.shareDescription);
info.finished = true;
// Stop running on foreground, otherwise share notification cannot be dismissed.
- stopForegroundWhenDone(id);
+ stopForegroundWhenDone(info.id);
triggerLocalNotification(mContext, info);
}
@@ -1214,7 +1034,11 @@ public class BugreportProgressService extends Service {
/**
* Build {@link Intent} that can be used to share the given bugreport.
*/
- private static Intent buildSendIntent(Context context, BugreportInfo info) {
+ private static Intent buildSendIntent(Context context, BugreportInfo info,
+ File screenshotsDir) {
+ // Rename files (if required) before sharing
+ info.renameBugreportFile();
+ info.renameScreenshots(screenshotsDir);
// Files are kept on private storage, so turn into Uris that we can
// grant temporary permissions for.
final Uri bugreportUri;
@@ -1300,7 +1124,7 @@ public class BugreportProgressService extends Service {
addDetailsToZipFile(info);
- final Intent sendIntent = buildSendIntent(mContext, info);
+ final Intent sendIntent = buildSendIntent(mContext, info, mScreenshotsDir);
if (sendIntent == null) {
Log.w(TAG, "Stopping progres on ID " + id + " because share intent could not be built");
synchronized (mLock) {
@@ -1628,12 +1452,11 @@ public class BugreportProgressService extends Service {
}
String action = intent.getAction();
if (action == null) {
- // Happens when BugreportReceiver calls startService...
+ // Happens when startService is called...
action = "no action";
}
final StringBuilder buffer = new StringBuilder(action).append(" extras: ");
addExtra(buffer, intent, EXTRA_ID);
- addExtra(buffer, intent, EXTRA_PID);
addExtra(buffer, intent, EXTRA_MAX);
addExtra(buffer, intent, EXTRA_NAME);
addExtra(buffer, intent, EXTRA_DESCRIPTION);
@@ -1678,15 +1501,6 @@ public class BugreportProgressService extends Service {
}
/**
- * Updates the system property used by {@code dumpstate} to rename the final bugreport files.
- */
- private boolean setBugreportNameProperty(int pid, String name) {
- Log.d(TAG, "Updating bugreport name to " + name);
- final String key = DUMPSTATE_PREFIX + pid + NAME_SUFFIX;
- return setSystemProperty(key, name);
- }
-
- /**
* Updates the user-provided details of a bugreport.
*/
private void updateBugreportInfo(int id, String name, String title, String description) {
@@ -1770,30 +1584,6 @@ public class BugreportProgressService extends Service {
private AlertDialog mDialog;
private Button mOkButton;
private int mId;
- private int mPid;
-
- /**
- * Last "committed" value of the bugreport name.
- * <p>
- * Once initially set, it's only updated when user clicks the OK button.
- */
- private String mSavedName;
-
- /**
- * Last value of the bugreport name as entered by the user.
- * <p>
- * Every time it's changed the equivalent system property is changed as well, but if the
- * user clicks CANCEL, the old value (stored on {@code mSavedName} is restored.
- * <p>
- * This logic handles the corner-case scenario where {@code dumpstate} finishes after the
- * user changed the name but didn't clicked OK yet (for example, because the user is typing
- * the description). The only drawback is that if the user changes the name while
- * {@code dumpstate} is running but clicks CANCEL after it finishes, then the final name
- * will be the one that has been canceled. But when {@code dumpstate} finishes the {code
- * name} UI is disabled and the old name restored anyways, so the user will be "alerted" of
- * such drawback.
- */
- private String mTempName;
/**
* Sets its internal state and displays the dialog.
@@ -1813,18 +1603,6 @@ public class BugreportProgressService extends Service {
mInfoName = (EditText) view.findViewById(R.id.name);
mInfoTitle = (EditText) view.findViewById(R.id.title);
mInfoDescription = (EditText) view.findViewById(R.id.description);
-
- mInfoName.setOnFocusChangeListener(new OnFocusChangeListener() {
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- return;
- }
- sanitizeName(info);
- }
- });
-
mDialog = new AlertDialog.Builder(themedContext)
.setView(view)
.setTitle(dialogTitle)
@@ -1839,15 +1617,6 @@ public class BugreportProgressService extends Service {
{
MetricsLogger.action(context,
MetricsEvent.ACTION_BUGREPORT_DETAILS_CANCELED);
- if (!mTempName.equals(mSavedName)) {
- // Must restore bugreport's name since it was changed
- // before user clicked OK.
- if (mUsingBugreportApi) {
- info.name = mSavedName;
- } else {
- setBugreportNameProperty(mPid, mSavedName);
- }
- }
}
})
.create();
@@ -1866,9 +1635,7 @@ public class BugreportProgressService extends Service {
}
// Then set fields.
- mSavedName = mTempName = info.name;
mId = info.id;
- mPid = info.pid;
if (!TextUtils.isEmpty(info.name)) {
mInfoName.setText(info.name);
}
@@ -1895,7 +1662,7 @@ public class BugreportProgressService extends Service {
@Override
public void onClick(View view) {
MetricsLogger.action(context, MetricsEvent.ACTION_BUGREPORT_DETAILS_SAVED);
- sanitizeName(info);
+ sanitizeName(info.name);
final String name = mInfoName.getText().toString();
final String title = mInfoTitle.getText().toString();
final String description = mInfoDescription.getText().toString();
@@ -1911,9 +1678,9 @@ public class BugreportProgressService extends Service {
* Sanitizes the user-provided value for the {@code name} field, automatically replacing
* invalid characters if necessary.
*/
- private void sanitizeName(BugreportInfo info) {
+ private void sanitizeName(String savedName) {
String name = mInfoName.getText().toString();
- if (name.equals(mTempName)) {
+ if (name.equals(savedName)) {
if (DEBUG) Log.v(TAG, "name didn't change, no need to sanitize: " + name);
return;
}
@@ -1933,28 +1700,6 @@ public class BugreportProgressService extends Service {
name = safeName.toString();
mInfoName.setText(name);
}
- mTempName = name;
- if (mUsingBugreportApi) {
- info.name = name;
- } else {
- // Must update system property for the cases where dumpstate finishes
- // while the user is still entering other fields (like title or
- // description)
- setBugreportNameProperty(mPid, name);
- }
- }
-
- /**
- * Notifies the dialog that the bugreport has finished so it disables the {@code name}
- * field.
- * <p>Once the bugreport is finished dumpstate has already generated the final files, so
- * changing the name would have no effect.
- */
- void onBugreportFinished() {
- if (mInfoName != null) {
- mInfoName.setEnabled(false);
- mInfoName.setText(mSavedName);
- }
}
void cancel() {
@@ -1976,18 +1721,10 @@ public class BugreportProgressService extends Service {
int id;
/**
- * {@code pid} of the {@code dumpstate} process generating the bugreport.
- * pid is unused in the API flow
- * TODO(b/136066578): Remove pid
- */
- final int pid;
-
- /**
* Prefix name of the bugreport, this is uneditable.
* The baseName consists of the string "bugreport" + deviceName + buildID
* This will end with the string "wifi"/"telephony" for wifi/telephony bugreports.
* Bugreport zip file name = "<baseName>-<name>.zip"
- * Bugreport png file name = "<baseName>-<name>.png"
*/
String baseName;
@@ -1998,6 +1735,12 @@ public class BugreportProgressService extends Service {
String name;
/**
+ * Initial value of the field name. This is required to rename the files later on, as they
+ * are created using initial value of name.
+ */
+ String initialName;
+
+ /**
* User-provided, one-line summary of the bug; when set, will be used as the subject
* of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
*/
@@ -2063,12 +1806,6 @@ public class BugreportProgressService extends Service {
boolean finished;
/**
- * Whether this bugreport is using API workflow.
- * TODO(b/136066578): Remove when legacy bugreport methods are removed
- */
- boolean usingApi;
-
- /**
* Whether the details entries have been added to the bugreport yet.
*/
boolean addingDetailsToZip;
@@ -2092,42 +1829,18 @@ public class BugreportProgressService extends Service {
int type;
/**
- * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
- */
- BugreportInfo(Context context, int id, int pid, String name, int max) {
- // bugreports triggered by STARTED broadcast do not use callback functions,
- // onFinished() callback method is the only function where type is used.
- // Set type to -1 as it is unused in this workflow.
- // This constructor will soon be removed.
- this(context, pid, "" /* dumpstate handles basename */, name, max, null, null, -1,
- false);
- this.id = id;
- }
-
- /**
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_REQUESTED.
*/
- BugreportInfo(Context context, int pid, String baseName, String name, int max,
+ BugreportInfo(Context context, String baseName, String name, int max,
@Nullable String shareTitle, @Nullable String shareDescription,
- @BugreportParams.BugreportMode int type, boolean usingApi) {
+ @BugreportParams.BugreportMode int type) {
this.context = context;
- this.pid = pid;
- this.name = name;
+ this.name = this.initialName = name;
this.max = this.realMax = max;
this.shareTitle = shareTitle == null ? "" : shareTitle;
this.shareDescription = shareDescription == null ? "" : shareDescription;
this.type = type;
this.baseName = baseName;
- this.usingApi = usingApi;
- }
-
- /**
- * Constructor for untracked bugreports - typically called upon receiving BUGREPORT_FINISHED
- * without a previous call to BUGREPORT_STARTED.
- */
- BugreportInfo(Context context, int id) {
- this(context, id, id, null, 0);
- this.finished = true;
}
ParcelFileDescriptor createBugreportFd() {
@@ -2136,17 +1849,24 @@ public class BugreportProgressService extends Service {
}
ParcelFileDescriptor createScreenshotFd() {
- File screenshotFile = new File(BUGREPORT_DIR, getFileName(this, ".png"));
+ File screenshotFile = new File(BUGREPORT_DIR, getScreenshotName("default"));
addScreenshot(screenshotFile);
return createReadWriteFile(screenshotFile);
}
/**
- * Gets the name for next screenshot file.
+ * Gets the name for next user triggered screenshot file.
*/
String getPathNextScreenshot() {
screenshotCounter ++;
- return "screenshot-" + pid + "-" + screenshotCounter + ".png";
+ return getScreenshotName(Integer.toString(screenshotCounter));
+ }
+
+ /**
+ * Gets the name for screenshot file based on the suffix that is passed.
+ */
+ String getScreenshotName(String suffix) {
+ return "screenshot-" + initialName + "-" + suffix + ".png";
}
/**
@@ -2157,7 +1877,8 @@ public class BugreportProgressService extends Service {
}
/**
- * Rename all screenshots files so that they contain the user-generated name instead of pid.
+ * Rename all screenshots files so that they contain the new {@code name} instead of the
+ * {@code initialName} if user has changed it.
*/
void renameScreenshots(File screenshotDir) {
if (TextUtils.isEmpty(name)) {
@@ -2166,22 +1887,21 @@ public class BugreportProgressService extends Service {
final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size());
for (File oldFile : screenshotFiles) {
final String oldName = oldFile.getName();
- final String newName;
- if (usingApi) {
- newName = getFileName(this, ".png");
- } else {
- newName = oldName.replaceFirst(Integer.toString(pid), name);
- }
+ final String newName = oldName.replaceFirst(initialName, name);
final File newFile;
if (!newName.equals(oldName)) {
final File renamedFile = new File(screenshotDir, newName);
Log.d(TAG, "Renaming screenshot file " + oldFile + " to " + renamedFile);
newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile;
} else {
- Log.w(TAG, "Name didn't change: " + oldName); // Shouldn't happen.
+ Log.w(TAG, "Name didn't change: " + oldName);
newFile = oldFile;
}
- renamedFiles.add(newFile);
+ if (newFile.length() > 0) {
+ renamedFiles.add(newFile);
+ } else if (newFile.delete()) {
+ Log.d(TAG, "screenshot file: " + newFile + "deleted successfully.");
+ }
}
screenshotFiles = renamedFiles;
}
@@ -2215,11 +1935,10 @@ public class BugreportProgressService extends Service {
final StringBuilder builder = new StringBuilder()
.append("\tid: ").append(id)
- .append(", pid: ").append(pid)
.append(", baseName: ").append(baseName)
.append(", name: ").append(name)
+ .append(", initialName: ").append(initialName)
.append(", finished: ").append(finished)
- .append(", usingApi: ").append(usingApi)
.append("\n\ttitle: ").append(title)
.append("\n\tdescription: ");
if (description == null) {
@@ -2250,9 +1969,9 @@ public class BugreportProgressService extends Service {
protected BugreportInfo(Parcel in) {
context = null;
id = in.readInt();
- pid = in.readInt();
baseName = in.readString();
name = in.readString();
+ initialName = in.readString();
title = in.readString();
description = in.readString();
max = in.readInt();
@@ -2269,7 +1988,6 @@ public class BugreportProgressService extends Service {
}
finished = in.readInt() == 1;
- usingApi = in.readInt() == 1;
screenshotCounter = in.readInt();
shareDescription = in.readString();
shareTitle = in.readString();
@@ -2278,9 +1996,9 @@ public class BugreportProgressService extends Service {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
- dest.writeInt(pid);
dest.writeString(baseName);
dest.writeString(name);
+ dest.writeString(initialName);
dest.writeString(title);
dest.writeString(description);
dest.writeInt(max);
@@ -2297,7 +2015,6 @@ public class BugreportProgressService extends Service {
}
dest.writeInt(finished ? 1 : 0);
- dest.writeInt(usingApi ? 1 : 0);
dest.writeInt(screenshotCounter);
dest.writeString(shareDescription);
dest.writeString(shareTitle);
@@ -2333,80 +2050,6 @@ public class BugreportProgressService extends Service {
}
- private final class DumpstateListener extends IDumpstateListener.Stub
- implements DeathRecipient {
-
- private final BugreportInfo info;
- private IDumpstateToken token;
-
- DumpstateListener(BugreportInfo info) {
- this.info = info;
- }
-
- /**
- * Connects to the {@code dumpstate} binder to receive updates.
- */
- boolean connect() {
- if (token != null) {
- Log.d(TAG, "connect(): " + info.id + " already connected");
- return true;
- }
- final IBinder service = ServiceManager.getService("dumpstate");
- if (service == null) {
- Log.d(TAG, "dumpstate service not bound yet");
- return true;
- }
- final IDumpstate dumpstate = IDumpstate.Stub.asInterface(service);
- try {
- token = dumpstate.setListener("Shell", this, /* perSectionDetails= */ false);
- if (token != null) {
- token.asBinder().linkToDeath(this, 0);
- }
- } catch (Exception e) {
- Log.e(TAG, "Could not set dumpstate listener: " + e);
- }
- return token != null;
- }
-
- @Override
- public void binderDied() {
- if (!info.finished) {
- // TODO: linkToDeath() might be called BEFORE Shell received the
- // BUGREPORT_FINISHED broadcast, in which case the statements below
- // spam logcat (but are harmless).
- // The right, long-term solution is to provide an onFinished() callback
- // on IDumpstateListener and call it instead of using a broadcast.
- Log.w(TAG, "Dumpstate process died:\n" + info);
- synchronized (mLock) {
- stopProgressLocked(info.id);
- }
- }
- token.asBinder().unlinkToDeath(this, 0);
- }
-
- @Override
- public void onProgress(int progress) throws RemoteException {
- synchronized (mLock) {
- checkProgressUpdatedLocked(info, progress);
- }
- }
-
- @Override
- public void onError(int errorCode) throws RemoteException {
- // TODO(b/111441001): implement
- }
-
- @Override
- public void onFinished() throws RemoteException {
- // TODO(b/111441001): implement
- }
-
- public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("token: "); pw.println(token);
- }
-
- }
-
@GuardedBy("mLock")
private void checkProgressUpdatedLocked(BugreportInfo info, int progress) {
if (progress > CAPPED_PROGRESS) {
@@ -2418,11 +2061,11 @@ public class BugreportProgressService extends Service {
private void updateProgressInfo(BugreportInfo info, int progress, int max) {
if (DEBUG) {
if (progress != info.progress) {
- Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+ Log.v(TAG, "Updating progress for name " + info.name + "(id: " + info.id
+ ") from " + info.progress + " to " + progress);
}
if (max != info.max) {
- Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+ Log.v(TAG, "Updating max progress for name " + info.name + "(id: " + info.id
+ ") from " + info.max + " to " + max);
}
}
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
deleted file mode 100644
index 15ce90fa6418..000000000000
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.shell;
-
-import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
-import static com.android.shell.BugreportProgressService.EXTRA_ORIGINAL_INTENT;
-import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.getFileExtra;
-import static com.android.shell.BugreportProgressService.dumpIntent;
-
-import java.io.File;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.FileUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-/**
- * Receiver that handles finished bugreports, usually by attaching them to an
- * {@link Intent#ACTION_SEND_MULTIPLE}.
- */
-public class BugreportReceiver extends BroadcastReceiver {
- private static final String TAG = "BugreportReceiver";
-
- /**
- * Always keep the newest 8 bugreport files.
- */
- private static final int MIN_KEEP_COUNT = 8;
-
- /**
- * Always keep bugreports taken in the last week.
- */
- private static final long MIN_KEEP_AGE = DateUtils.WEEK_IN_MILLIS;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "onReceive(): " + dumpIntent(intent));
- // Clean up older bugreports in background
- cleanupOldFiles(this, intent, INTENT_BUGREPORT_FINISHED, MIN_KEEP_COUNT, MIN_KEEP_AGE);
-
- // Delegate intent handling to service.
- Intent serviceIntent = new Intent(context, BugreportProgressService.class);
- serviceIntent.putExtra(EXTRA_ORIGINAL_INTENT, intent);
- context.startService(serviceIntent);
- }
-
- static void cleanupOldFiles(BroadcastReceiver br, Intent intent, String expectedAction,
- final int minCount, final long minAge) {
- if (!expectedAction.equals(intent.getAction())) {
- return;
- }
- final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
- if (bugreportFile == null || !bugreportFile.exists()) {
- Log.e(TAG, "Not deleting old files because file " + bugreportFile + " doesn't exist");
- return;
- }
- final PendingResult result = br.goAsync();
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- try {
- FileUtils.deleteOlderFiles(bugreportFile.getParentFile(), minCount, minAge);
- } catch (RuntimeException e) {
- Log.e(TAG, "RuntimeException deleting old files", e);
- }
- result.finish();
- return null;
- }
- }.execute();
- }
-}
diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
deleted file mode 100644
index 634c3b47c787..000000000000
--- a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.shell;
-
-import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
-import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.getFileExtra;
-import static com.android.shell.BugreportProgressService.getUri;
-import static com.android.shell.BugreportReceiver.cleanupOldFiles;
-
-import java.io.File;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.text.format.DateUtils;
-
-/**
- * Receiver that handles finished remote bugreports, by re-sending
- * the intent with appended bugreport zip file URI.
- *
- * <p> Remote bugreport never contains a screenshot.
- */
-public class RemoteBugreportReceiver extends BroadcastReceiver {
-
- private static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
-
- /** Always keep just the last remote bugreport's files around. */
- private static final int REMOTE_BUGREPORT_FILES_AMOUNT = 3;
-
- /** Always keep remote bugreport files created in the last day. */
- private static final long MIN_KEEP_AGE = DateUtils.DAY_IN_MILLIS;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- cleanupOldFiles(this, intent, INTENT_REMOTE_BUGREPORT_FINISHED,
- REMOTE_BUGREPORT_FILES_AMOUNT, MIN_KEEP_AGE);
-
- final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
- final Uri bugreportUri = getUri(context, bugreportFile);
- final String bugreportHash = intent.getStringExtra(
- DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
-
- final Intent newIntent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
- newIntent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
- newIntent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
- context.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM,
- android.Manifest.permission.DUMP);
- }
-}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 3a71632cf1ca..bb298e937fbb 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -29,10 +29,8 @@ import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.EXTRA_ID;
import static com.android.shell.BugreportProgressService.EXTRA_MAX;
import static com.android.shell.BugreportProgressService.EXTRA_NAME;
-import static com.android.shell.BugreportProgressService.EXTRA_PID;
import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
import static org.junit.Assert.assertEquals;
@@ -145,6 +143,10 @@ public class BugreportReceiverTest {
private static final String TITLE2 = "Master of the Universe";
private static final String DESCRIPTION = "One's description...";
private static final String DESCRIPTION2 = "...is another's treasure.";
+ // TODO(b/143130523): Fix (update) tests and add to presubmit
+ private static final String EXTRA_PID = "android.intent.extra.PID";
+ private static final String INTENT_BUGREPORT_STARTED =
+ "com.android.internal.intent.action.BUGREPORT_STARTED";
private static final String NO_DESCRIPTION = null;
private static final String NO_NAME = null;
diff --git a/packages/SystemUI/res/layout/qqs_media_panel.xml b/packages/SystemUI/res/layout/qqs_media_panel.xml
new file mode 100644
index 000000000000..1189371fc7f1
--- /dev/null
+++ b/packages/SystemUI/res/layout/qqs_media_panel.xml
@@ -0,0 +1,100 @@
+<?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
+ -->
+
+<!-- Layout for QQS media controls -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qqs_media_controls"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:padding="10dp"
+ >
+ <!-- Top line: icon + artist name -->
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:gravity="center"
+ >
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="15dp"
+ android:layout_height="15dp"
+ android:layout_marginEnd="5dp"
+ />
+ <TextView
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:singleLine="true"
+ />
+ </LinearLayout>
+
+ <!-- Second line: song name -->
+ <TextView
+ android:id="@+id/header_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:gravity="center"/>
+
+ <!-- Bottom section: controls -->
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ >
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action0"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action1"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action2"
+ />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
new file mode 100644
index 000000000000..dd422766c153
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -0,0 +1,124 @@
+<?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
+ -->
+
+<!-- Layout for media controls inside QSPanel carousel -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qs_media_controls"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center_horizontal|fill_vertical"
+ android:padding="10dp"
+ >
+
+ <!-- placeholder for notification header -->
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/header"
+ android:padding="3dp"
+ android:layout_marginEnd="-12dp"
+ />
+
+ <!-- Top line: artist name -->
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ >
+ <TextView
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:singleLine="true"
+ />
+ </LinearLayout>
+
+ <!-- Second line: song name -->
+ <TextView
+ android:id="@+id/header_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:gravity="center"/>
+
+ <!-- Bottom section: controls -->
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ >
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action0"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action1"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action2"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action3"
+ />
+ <ImageButton
+ style="@android:style/Widget.Material.Button.Borderless.Small"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:layout_marginEnd="2dp"
+ android:gravity="center"
+ android:visibility="gone"
+ android:id="@+id/action4"
+ />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index ed18dc728402..e99b91787072 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -43,7 +43,7 @@
<com.android.systemui.qs.QuickQSPanel
android:id="@+id/quick_qs_panel"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:layout_below="@id/quick_qs_status_icons"
android:layout_marginStart="@dimen/qs_header_tile_margin_horizontal"
android:layout_marginEnd="@dimen/qs_header_tile_margin_horizontal"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d722d618e416..14371fe4b41b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1164,4 +1164,11 @@
<!-- Size of the RAT type for CellularTile -->
<dimen name="celltile_rat_type_size">10sp</dimen>
+
+ <dimen name="new_qs_vertical_margin">8dp</dimen>
+
+ <!-- Size of media cards in the QSPanel carousel -->
+ <dimen name="qs_media_height">150dp</dimen>
+ <dimen name="qs_media_width">350dp</dimen>
+ <dimen name="qs_media_padding">8dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index ebac3d9da5e1..caee8ccb6970 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -131,8 +131,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
protected void verifyPasswordAndUnlock() {
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
- final LockscreenCredential password =
- LockscreenCredential.createPassword(getPasswordText());
+ final LockscreenCredential password = getEnteredCredential();
setPasswordEntryInputEnabled(false);
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
@@ -223,7 +222,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
protected abstract void resetPasswordText(boolean animate, boolean announce);
- protected abstract CharSequence getPasswordText();
+ protected abstract LockscreenCredential getEnteredCredential();
protected abstract void setPasswordEntryEnabled(boolean enabled);
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 12c9fc9ce536..f8f3dc8d6ecd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -36,6 +36,7 @@ import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.R;
@@ -243,8 +244,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
@Override
- protected CharSequence getPasswordText() {
- return mPasswordEntry.getText();
+ protected LockscreenCredential getEnteredCredential() {
+ return LockscreenCredential.createPasswordOrNone(mPasswordEntry.getText());
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 8e9df5563123..c67deccb1f62 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -23,6 +23,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
/**
@@ -167,8 +168,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
@Override
- protected CharSequence getPasswordText() {
- return mPasswordEntry.getText();
+ protected LockscreenCredential getEnteredCredential() {
+ return LockscreenCredential.createPinOrNone(mPasswordEntry.getText());
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ac5e255289cf..27410be09db0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -39,7 +39,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
import android.annotation.AnyThread;
import android.annotation.MainThread;
@@ -101,6 +100,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainLooper;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -118,7 +118,6 @@ import java.util.TimeZone;
import java.util.function.Consumer;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -1500,7 +1499,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
@VisibleForTesting
@Inject
- protected KeyguardUpdateMonitor(Context context, @Named(MAIN_LOOPER_NAME) Looper mainLooper) {
+ protected KeyguardUpdateMonitor(Context context, @MainLooper Looper mainLooper) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ff8a932a6a92..486d02c207db 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -40,6 +40,10 @@ import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.MainLooper;
import com.android.systemui.dock.DockManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -148,16 +152,16 @@ public class Dependency {
/**
* Key for getting a the main looper.
*/
- public static final String MAIN_LOOPER_NAME = "main_looper";
+ private static final String MAIN_LOOPER_NAME = "main_looper";
/**
* Key for getting a background Looper for background work.
*/
- public static final String BG_LOOPER_NAME = "background_looper";
+ private static final String BG_LOOPER_NAME = "background_looper";
/**
* Key for getting a background Handler for background work.
*/
- public static final String BG_HANDLER_NAME = "background_handler";
+ private static final String BG_HANDLER_NAME = "background_handler";
/**
* Key for getting a Handler for receiving time tick broadcasts on.
*/
@@ -165,7 +169,7 @@ public class Dependency {
/**
* Generic handler on the main thread.
*/
- public static final String MAIN_HANDLER_NAME = "main_handler";
+ private static final String MAIN_HANDLER_NAME = "main_handler";
/**
* An email address to send memory leak reports to by default.
@@ -300,10 +304,10 @@ public class Dependency {
@Inject Lazy<AutoHideController> mAutoHideController;
@Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
@Inject Lazy<PrivacyItemController> mPrivacyItemController;
- @Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
- @Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
- @Inject @Named(MAIN_LOOPER_NAME) Lazy<Looper> mMainLooper;
- @Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
+ @Inject @BgLooper Lazy<Looper> mBgLooper;
+ @Inject @BgHandler Lazy<Handler> mBgHandler;
+ @Inject @MainLooper Lazy<Looper> mMainLooper;
+ @Inject @MainHandler Lazy<Handler> mMainHandler;
@Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler;
@Nullable
@Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
index aa13fa834f56..746515a816b3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -27,6 +27,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.AppComponentFactory;
+import com.android.systemui.dagger.ContextComponentHelper;
+
import javax.inject.Inject;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 91776a335f0d..022bf06838a6 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -34,6 +34,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.TimingsTraceLog;
+import com.android.systemui.dagger.ContextComponentHelper;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 11db481a425b..0a547b6bf051 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -27,6 +27,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.dagger.DaggerSystemUIRootComponent;
+import com.android.systemui.dagger.DependencyProvider;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -107,7 +110,7 @@ public class SystemUIFactory {
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
return DaggerSystemUIRootComponent.builder()
- .dependencyProvider(new com.android.systemui.DependencyProvider())
+ .dependencyProvider(new DependencyProvider())
.contextHolder(new ContextHolder(context))
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index ef171d305d28..f616d57e90aa 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.appops;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -31,6 +29,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.BgLooper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -39,7 +38,6 @@ import java.util.List;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -79,7 +77,7 @@ public class AppOpsControllerImpl implements AppOpsController,
};
@Inject
- public AppOpsControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper) {
+ public AppOpsControllerImpl(Context context, @BgLooper Looper bgLooper) {
this(context, bgLooper, new PermissionFlagsCache(context));
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 5e977b4684dc..ff4711cb208a 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -26,13 +26,12 @@ import android.os.UserHandle
import android.util.Log
import android.util.SparseArray
import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.Dependency.BG_LOOPER_NAME
-import com.android.systemui.Dependency.MAIN_HANDLER_NAME
import com.android.systemui.Dumpable
+import com.android.systemui.dagger.qualifiers.BgLooper
+import com.android.systemui.dagger.qualifiers.MainHandler
import java.io.FileDescriptor
import java.io.PrintWriter
import javax.inject.Inject
-import javax.inject.Named
import javax.inject.Singleton
data class ReceiverData(
@@ -61,8 +60,8 @@ private const val DEBUG = false
@Singleton
open class BroadcastDispatcher @Inject constructor (
private val context: Context,
- @Named(MAIN_HANDLER_NAME) private val mainHandler: Handler,
- @Named(BG_LOOPER_NAME) private val bgLooper: Looper
+ @MainHandler private val mainHandler: Handler,
+ @BgLooper private val bgLooper: Looper
) : Dumpable {
// Only modify in BG thread
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 914258f48b46..db85fa0a3203 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -17,7 +17,6 @@
package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_MANAGER_ENABLED;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
import android.content.Context;
import android.hardware.SensorManager;
@@ -31,6 +30,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
import com.android.systemui.classifier.brightline.FalsingDataProvider;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingPlugin;
import com.android.systemui.plugins.PluginListener;
@@ -41,7 +41,6 @@ import com.android.systemui.util.sensors.ProximitySensor;
import java.io.PrintWriter;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -62,7 +61,7 @@ public class FalsingManagerProxy implements FalsingManager {
@Inject
FalsingManagerProxy(Context context, PluginManager pluginManager,
- @Named(MAIN_HANDLER_NAME) Handler handler,
+ @MainHandler Handler handler,
ProximitySensor proximitySensor,
DeviceConfigProxy deviceConfig) {
mProximitySensor = proximitySensor;
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java
index 2c8a67270d94..4be610fcd9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/ActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import android.app.Activity;
+import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.tuner.TunerActivity;
import dagger.Binds;
diff --git a/packages/SystemUI/src/com/android/systemui/ComponentBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
index 3b35c61e8eb2..4e4c06e9d447 100644
--- a/packages/SystemUI/src/com/android/systemui/ComponentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import dagger.Binds;
import dagger.Module;
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
index 2cf0f8dafcad..d6d1e418240a 100644
--- a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import android.app.Activity;
import android.app.Service;
+import com.android.systemui.SystemUI;
+
/**
* Interface necessary to make Dagger happy. See {@link ContextComponentResolver}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
index 995263240e2d..d7822c9fc6da 100644
--- a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import android.app.Activity;
import android.app.Service;
+import com.android.systemui.SystemUI;
+
import java.util.Map;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index f9f0f1bad2fa..6674c12ab613 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
+import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.classifier.FalsingManagerProxy;
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 8c1f8ac91916..87434f344729 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,51 +14,35 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
-import static com.android.systemui.Dependency.BG_HANDLER_NAME;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.IActivityManager;
import android.app.INotificationManager;
-import android.app.IWallpaperManager;
-import android.app.WallpaperManager;
import android.content.Context;
-import android.content.res.Resources;
-import android.hardware.SensorPrivacyManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
-import android.os.PowerManager;
import android.os.Process;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.view.IWindowManager;
-import android.view.WindowManager;
-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.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.MainLooper;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.plugins.PluginInitializerImpl;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -70,11 +54,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.util.leak.LeakDetector;
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
import javax.inject.Named;
-import javax.inject.Qualifier;
import javax.inject.Singleton;
import dagger.Module;
@@ -82,16 +62,14 @@ import dagger.Provides;
/**
* Provides dependencies for the root component of sysui injection.
+ *
+ * Only SystemUI owned classes and instances should go in here. Other, framework-owned classes
+ * should go in {@link SystemServicesModule}.
+ *
* See SystemUI/docs/dagger.md
*/
@Module
public class DependencyProvider {
- @Qualifier
- @Documented
- @Retention(RUNTIME)
- public @interface MainResources {
- // TODO: use attribute to get other, non-main resources?
- }
@Singleton
@Provides
@@ -104,7 +82,7 @@ public class DependencyProvider {
@Singleton
@Provides
- @Named(BG_LOOPER_NAME)
+ @BgLooper
public Looper provideBgLooper() {
HandlerThread thread = new HandlerThread("SysUiBg",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -113,29 +91,34 @@ public class DependencyProvider {
}
/** Main Looper */
- @Singleton
@Provides
- @Named(MAIN_LOOPER_NAME)
+ @MainLooper
public Looper provideMainLooper() {
return Looper.getMainLooper();
}
@Singleton
@Provides
- @Named(BG_HANDLER_NAME)
- public Handler provideBgHandler(@Named(BG_LOOPER_NAME) Looper bgLooper) {
+ @BgHandler
+ public Handler provideBgHandler(@BgLooper Looper bgLooper) {
return new Handler(bgLooper);
}
@Singleton
@Provides
- @Named(MAIN_HANDLER_NAME)
- public Handler provideMainHandler(@Named(MAIN_LOOPER_NAME) Looper mainLooper) {
+ @MainHandler
+ public Handler provideMainHandler(@MainLooper Looper mainLooper) {
return new Handler(mainLooper);
}
/** */
@Provides
+ public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
+ return new AmbientDisplayConfiguration(context);
+ }
+
+ /** */
+ @Provides
public Handler provideHandler() {
return new Handler();
}
@@ -148,23 +131,10 @@ public class DependencyProvider {
@Singleton
@Provides
- @Nullable
- public LocalBluetoothManager provideLocalBluetoothController(Context context,
- @Named(BG_HANDLER_NAME) Handler bgHandler) {
- return LocalBluetoothManager.create(context, bgHandler,
- UserHandle.ALL);
- }
-
- @Singleton
- @Provides
- public MetricsLogger provideMetricsLogger() {
- return new MetricsLogger();
- }
-
- @Singleton
- @Provides
- public IWindowManager provideIWindowManager() {
- return WindowManagerGlobal.getWindowManagerService();
+ // Single instance of DisplayMetrics, gets updated by StatusBar, but can be used
+ // anywhere it is needed.
+ public DisplayMetrics provideDisplayMetrics() {
+ return new DisplayMetrics();
}
@Singleton
@@ -184,29 +154,21 @@ public class DependencyProvider {
@Singleton
@Provides
- // Single instance of DisplayMetrics, gets updated by StatusBar, but can be used
- // anywhere it is needed.
- public DisplayMetrics provideDisplayMetrics() {
- return new DisplayMetrics();
- }
+ public LeakDetector provideLeakDetector() {
+ return LeakDetector.create();
- @Singleton
- @Provides
- public SensorPrivacyManager provideSensorPrivacyManager(Context context) {
- return context.getSystemService(SensorPrivacyManager.class);
}
@Singleton
@Provides
- public LeakDetector provideLeakDetector() {
- return LeakDetector.create();
-
+ public MetricsLogger provideMetricsLogger() {
+ return new MetricsLogger();
}
@Singleton
@Provides
public NightDisplayListener provideNightDisplayListener(Context context,
- @Named(BG_HANDLER_NAME) Handler bgHandler) {
+ @BgHandler Handler bgHandler) {
return new NightDisplayListener(context, bgHandler);
}
@@ -219,7 +181,7 @@ public class DependencyProvider {
@Singleton
@Provides
public NavigationBarController provideNavigationBarController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ @MainHandler Handler mainHandler) {
return new NavigationBarController(context, mainHandler);
}
@@ -232,7 +194,7 @@ public class DependencyProvider {
@Singleton
@Provides
public AutoHideController provideAutoHideController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler,
+ @MainHandler Handler mainHandler,
NotificationRemoteInputManager notificationRemoteInputManager,
IWindowManager iWindowManager) {
return new AutoHideController(context, mainHandler, notificationRemoteInputManager,
@@ -253,25 +215,12 @@ public class DependencyProvider {
@Singleton
@Provides
- public PackageManagerWrapper providePackageManagerWrapper() {
- return PackageManagerWrapper.getInstance();
- }
-
- @Singleton
- @Provides
public DeviceProvisionedController provideDeviceProvisionedController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ @MainHandler Handler mainHandler) {
return new DeviceProvisionedControllerImpl(context, mainHandler);
}
/** */
- @Singleton
- @Provides
- public AlarmManager provideAlarmManager(Context context) {
- return context.getSystemService(AlarmManager.class);
- }
-
- /** */
@Provides
public LockPatternUtils provideLockPatternUtils(Context context) {
return new LockPatternUtils(context);
@@ -279,52 +228,7 @@ public class DependencyProvider {
/** */
@Provides
- public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
- return new AmbientDisplayConfiguration(context);
- }
-
- /** */
- @Provides
public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
return new AlwaysOnDisplayPolicy(context);
}
-
- /** */
- @Provides
- public PowerManager providePowerManager(Context context) {
- return context.getSystemService(PowerManager.class);
- }
-
- /** */
- @Provides
- @MainResources
- public Resources provideResources(Context context) {
- return context.getResources();
- }
-
- /** */
- @Provides
- @Nullable
- public IWallpaperManager provideIWallpaperManager() {
- return IWallpaperManager.Stub.asInterface(
- ServiceManager.getService(Context.WALLPAPER_SERVICE));
- }
-
- /** */
- @Provides
- public WallpaperManager providesWallpaperManager(Context context) {
- return (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
- }
-
- /** */
- @Provides
- public WindowManager providesWindowManager(Context context) {
- return context.getSystemService(WindowManager.class);
- }
-
- /** */
- @Provides
- public IActivityManager providesIActivityManager() {
- return ActivityManager.getService();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java
index c11236ebae53..1f2c0a18f928 100644
--- a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import android.app.Service;
+import com.android.systemui.ImageWallpaper;
import com.android.systemui.doze.DozeService;
import com.android.systemui.keyguard.KeyguardService;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
new file mode 100644
index 000000000000..891bf615b8f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -0,0 +1,123 @@
+/*
+ * 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.dagger;
+
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.IActivityManager;
+import android.app.IWallpaperManager;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.MainResources;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides Non-SystemUI, Framework-Owned instances to the dependency graph.
+ */
+@Module
+public class SystemServicesModule {
+
+ @Singleton
+ @Provides
+ static AlarmManager provideAlarmManager(Context context) {
+ return context.getSystemService(AlarmManager.class);
+ }
+
+ @Singleton
+ @Provides
+ static IActivityManager provideIActivityManager() {
+ return ActivityManager.getService();
+ }
+
+ @Provides
+ @Nullable
+ static IWallpaperManager provideIWallPaperManager() {
+ return IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
+ }
+
+ @Singleton
+ @Provides
+ static IWindowManager provideIWindowManager() {
+ return WindowManagerGlobal.getWindowManagerService();
+ }
+
+ @SuppressLint("MissingPermission")
+ @Singleton
+ @Provides
+ @Nullable
+ static LocalBluetoothManager provideLocalBluetoothController(Context context,
+ @BgHandler Handler bgHandler) {
+ return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
+ }
+
+ @Singleton
+ @Provides
+ static PackageManagerWrapper providePackageManagerWrapper() {
+ return PackageManagerWrapper.getInstance();
+ }
+
+ /** */
+ @Singleton
+ @Provides
+ static PowerManager providePowerManager(Context context) {
+ return context.getSystemService(PowerManager.class);
+ }
+
+ @Provides
+ @MainResources
+ static Resources provideResources(Context context) {
+ return context.getResources();
+ }
+
+ @Singleton
+ @Provides
+ static SensorPrivacyManager provideSensorPrivacyManager(Context context) {
+ return context.getSystemService(SensorPrivacyManager.class);
+ }
+
+ @Provides
+ static WallpaperManager provideWallpaperManager(Context context) {
+ return (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
+ }
+
+ @Singleton
+ @Provides
+ static WindowManager provideWindowManager(Context context) {
+ return context.getSystemService(WindowManager.class);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index a5a55983fe51..49cd414f9d9e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
+import com.android.systemui.SystemUI;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 176bcbfd9500..c95b50b195b3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import androidx.annotation.Nullable;
+import com.android.systemui.SystemUI;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.power.EnhancedEstimates;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 4520a1a6a037..30f13979e66e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import android.annotation.Nullable;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index bcbe672fbe97..113c9c845d95 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.dagger;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import android.content.ContentProvider;
+import com.android.systemui.Dependency;
+import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.InjectionInflationController;
@@ -36,6 +39,7 @@ import dagger.Component;
@Component(modules = {
DependencyProvider.class,
DependencyBinder.class,
+ SystemServicesModule.class,
SystemUIFactory.ContextHolder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
new file mode 100644
index 000000000000..bc6b83ba1def
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgHandler.java
@@ -0,0 +1,30 @@
+/*
+ * 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BgHandler {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java
new file mode 100644
index 000000000000..2aadda1215d5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BgLooper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BgLooper {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java
new file mode 100644
index 000000000000..79661fa4a738
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainHandler.java
@@ -0,0 +1,30 @@
+/*
+ * 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MainHandler {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java
new file mode 100644
index 000000000000..750d7d72035c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainLooper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MainLooper {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java
new file mode 100644
index 000000000000..3daeda550b4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/MainResources.java
@@ -0,0 +1,31 @@
+/*
+ * 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.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MainResources {
+ // TODO: use attribute to get other, non-main resources?
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 1a6bd60816b3..d1047e216ec4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -68,6 +68,12 @@ public interface DozeHost {
*/
void prepareForGentleSleep(Runnable onDisplayOffCallback);
+ /**
+ * Cancel pending {@code onDisplayOffCallback} callback.
+ * @see #prepareForGentleSleep(Runnable)
+ */
+ void cancelGentleSleep();
+
void onIgnoreTouchWhilePulsing(boolean ignore);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 95c42fcd175c..e1b4f3122861 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -71,7 +71,7 @@ public class DozeScreenState implements DozeMachine.Part {
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState(mParameters);
- mDozeHost.prepareForGentleSleep(null);
+ mDozeHost.cancelGentleSleep();
if (newState == DozeMachine.State.FINISH) {
// Make sure not to apply the screen state after DozeService was destroyed.
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index b4cc571be061..1b4857ebb209 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -22,7 +22,7 @@ import android.view.View;
import com.android.systemui.ConfigurationChangedReceiver;
import com.android.systemui.Dumpable;
-import com.android.systemui.SystemUIRootComponent;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.phone.NavigationBarFragment;
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 631b8b7a14a0..22fb4c0dbdb5 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -22,25 +22,20 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
-import android.os.Handler
-import android.os.Looper
-import android.os.Message
-import android.os.UserHandle
-import android.os.UserManager
+import android.os.*
import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-import com.android.systemui.Dependency.BG_HANDLER_NAME
-import com.android.systemui.Dependency.MAIN_HANDLER_NAME
+import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
-import com.android.systemui.Dumpable
+import com.android.systemui.dagger.qualifiers.BgHandler
+import com.android.systemui.dagger.qualifiers.MainHandler
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.ref.WeakReference
import javax.inject.Inject
-import javax.inject.Named
import javax.inject.Singleton
fun isPermissionsHubEnabled() = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
@@ -50,8 +45,8 @@ fun isPermissionsHubEnabled() = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_P
class PrivacyItemController @Inject constructor(
val context: Context,
private val appOpsController: AppOpsController,
- @Named(MAIN_HANDLER_NAME) private val uiHandler: Handler,
- @Named(BG_HANDLER_NAME) private val bgHandler: Handler
+ @MainHandler private val uiHandler: Handler,
+ @BgHandler private val bgHandler: Handler
) : Dumpable {
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
new file mode 100644
index 000000000000..f710f7fc47e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.qs
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.qs.TileLayout.exactly
+
+class DoubleLineTileLayout(context: Context) : ViewGroup(context), QSPanel.QSTileLayout {
+
+ protected val mRecords = ArrayList<QSPanel.TileRecord>()
+ private var _listening = false
+ private var smallTileSize = 0
+ private val twoLineHeight
+ get() = smallTileSize * 2 + cellMarginVertical
+ private var cellMarginHorizontal = 0
+ private var cellMarginVertical = 0
+
+ init {
+ isFocusableInTouchMode = true
+ clipChildren = false
+ clipToPadding = false
+
+ updateResources()
+ }
+
+ override fun addTile(tile: QSPanel.TileRecord) {
+ mRecords.add(tile)
+ tile.tile.setListening(this, _listening)
+ addTileView(tile)
+ }
+
+ protected fun addTileView(tile: QSPanel.TileRecord) {
+ addView(tile.tileView)
+ }
+
+ override fun removeTile(tile: QSPanel.TileRecord) {
+ mRecords.remove(tile)
+ tile.tile.setListening(this, false)
+ removeView(tile.tileView)
+ }
+
+ override fun removeAllViews() {
+ mRecords.forEach { it.tile.setListening(this, false) }
+ mRecords.clear()
+ super.removeAllViews()
+ }
+
+ override fun getOffsetTop(tile: QSPanel.TileRecord?) = top
+
+ override fun updateResources(): Boolean {
+ with(mContext.resources) {
+ smallTileSize = getDimensionPixelSize(R.dimen.qs_quick_tile_size)
+ cellMarginHorizontal = getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal)
+ cellMarginVertical = getDimensionPixelSize(R.dimen.new_qs_vertical_margin)
+ }
+ requestLayout()
+ return false
+ }
+
+ override fun setListening(listening: Boolean) {
+ if (_listening == listening) return
+ _listening = listening
+ for (record in mRecords) {
+ record.tile.setListening(this, listening)
+ }
+ }
+
+ override fun getNumVisibleTiles() = mRecords.size
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ updateResources()
+ }
+
+ override fun onFinishInflate() {
+ updateResources()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ var previousView: View = this
+ var tiles = 0
+
+ mRecords.forEach {
+ val tileView = it.tileView
+ if (tileView.visibility != View.GONE) {
+ tileView.updateAccessibilityOrder(previousView)
+ previousView = tileView
+ tiles++
+ tileView.measure(exactly(smallTileSize), exactly(smallTileSize))
+ }
+ }
+
+ val height = twoLineHeight
+ val columns = tiles / 2
+ val width = paddingStart + paddingEnd +
+ columns * smallTileSize +
+ (columns - 1) * cellMarginHorizontal
+ setMeasuredDimension(width, height)
+ }
+
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ val tiles = mRecords.filter { it.tileView.visibility != View.GONE }
+ tiles.forEachIndexed {
+ index, tile ->
+ val column = index % (tiles.size / 2)
+ val left = getLeftForColumn(column)
+ val top = if (index < tiles.size / 2) 0 else getTopBottomRow()
+ tile.tileView.layout(left, top, left + smallTileSize, top + smallTileSize)
+ }
+ }
+
+ private fun getLeftForColumn(column: Int) = column * (smallTileSize + cellMarginHorizontal)
+
+ private fun getTopBottomRow() = smallTileSize + cellMarginVertical
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 9221b6852112..a267bbb92ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
@@ -267,6 +268,17 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
mAllViews.add(tileView);
count++;
}
+
+
+ int flag = Settings.System.getInt(mQsPanel.getContext().getContentResolver(),
+ "qs_media_player", 0);
+ if (flag == 1) {
+ View qsMediaView = mQsPanel.getMediaPanel();
+ View qqsMediaView = mQuickQsPanel.getMediaPlayer().getView();
+ translationXBuilder.addFloat(qsMediaView, "alpha", 0, 1);
+ translationXBuilder.addFloat(qqsMediaView, "alpha", 1, 0);
+ }
+
if (mAllowFancy) {
// Make brightness appear static position and alpha in through second half.
View brightness = mQsPanel.getBrightnessView();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index b9f3a7fcc63b..5742787b39bc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -17,9 +17,7 @@
package com.android.systemui.qs;
import static com.android.systemui.Dependency.BG_HANDLER;
-import static com.android.systemui.Dependency.BG_HANDLER_NAME;
import static com.android.systemui.Dependency.MAIN_LOOPER;
-import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.annotation.MainThread;
@@ -41,6 +39,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.keyguard.CarrierTextController;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.MainLooper;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -77,8 +77,8 @@ public class QSCarrierGroup extends LinearLayout implements
@Inject
public QSCarrierGroup(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
NetworkController networkController, ActivityStarter activityStarter,
- @Named(BG_HANDLER_NAME) Handler handler,
- @Named(MAIN_LOOPER_NAME) Looper looper) {
+ @BgHandler Handler handler,
+ @MainLooper Looper looper) {
super(context, attrs);
mNetworkController = networkController;
mActivityStarter = activityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
new file mode 100644
index 000000000000..af418f6308a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -0,0 +1,301 @@
+/*
+ * 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.qs;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.RippleDrawable;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.settingslib.media.MediaOutputSliceConstants;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.MediaTransferManager;
+
+/**
+ * Single media player for carousel in QSPanel
+ */
+public class QSMediaPlayer {
+
+ private static final String TAG = "QSMediaPlayer";
+
+ private Context mContext;
+ private LinearLayout mMediaNotifView;
+ private MediaSession.Token mToken;
+ private MediaController mController;
+ private int mWidth;
+ private int mHeight;
+
+ /**
+ *
+ * @param context
+ * @param parent
+ * @param width
+ * @param height
+ */
+ public QSMediaPlayer(Context context, ViewGroup parent, int width, int height) {
+ mContext = context;
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mMediaNotifView = (LinearLayout) inflater.inflate(R.layout.qs_media_panel, parent, false);
+
+ mWidth = width;
+ mHeight = height;
+ }
+
+ public View getView() {
+ return mMediaNotifView;
+ }
+
+ /**
+ *
+ * @param token token for this media session
+ * @param icon app notification icon
+ * @param iconColor foreground color (for text, icons)
+ * @param bgColor background color
+ * @param actionsContainer a LinearLayout containing the media action buttons
+ * @param notif
+ */
+ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
+ View actionsContainer, Notification notif) {
+ Log.d(TAG, "got media session: " + token);
+ mToken = token;
+ mController = new MediaController(mContext, token);
+ MediaMetadata mMediaMetadata = mController.getMetadata();
+ Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
+
+ // Album art
+ addAlbumArtBackground(mMediaMetadata, bgColor, mWidth, mHeight);
+
+ // Reuse notification header instead of reimplementing everything
+ RemoteViews headerRemoteView = builder.makeNotificationHeader();
+ LinearLayout headerView = mMediaNotifView.findViewById(R.id.header);
+ View result = headerRemoteView.apply(mContext, headerView);
+ result.setPadding(0, 0, 0, 0);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, 75);
+ result.setLayoutParams(lp);
+ headerView.removeAllViews();
+ headerView.addView(result);
+
+ View seamless = headerView.findViewById(com.android.internal.R.id.media_seamless);
+ seamless.setVisibility(View.VISIBLE);
+
+ // App icon
+ ImageView appIcon = headerView.findViewById(com.android.internal.R.id.icon);
+ Drawable iconDrawable = icon.loadDrawable(mContext);
+ iconDrawable.setTint(iconColor);
+ appIcon.setImageDrawable(iconDrawable);
+
+ // App title
+ TextView appName = headerView.findViewById(com.android.internal.R.id.app_name_text);
+ String appNameString = builder.loadHeaderAppName();
+ appName.setText(appNameString);
+ appName.setTextColor(iconColor);
+
+ // Action
+ mMediaNotifView.setOnClickListener(v -> {
+ try {
+ notif.contentIntent.send();
+ // Also close shade
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled");
+ e.printStackTrace();
+ }
+ });
+
+ // Separator
+ TextView separator = headerView.findViewById(com.android.internal.R.id.header_text_divider);
+ separator.setTextColor(iconColor);
+
+ // Album name
+ TextView albumName = headerView.findViewById(com.android.internal.R.id.header_text);
+ String albumString = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
+ if (!albumString.isEmpty()) {
+ albumName.setText(albumString);
+ albumName.setTextColor(iconColor);
+ albumName.setVisibility(View.VISIBLE);
+ separator.setVisibility(View.VISIBLE);
+ } else {
+ albumName.setVisibility(View.GONE);
+ separator.setVisibility(View.GONE);
+ }
+
+ // Transfer chip
+ MediaTransferManager mediaTransferManager = new MediaTransferManager(mContext);
+ View transferBackgroundView = headerView.findViewById(
+ com.android.internal.R.id.media_seamless);
+ LinearLayout viewLayout = (LinearLayout) transferBackgroundView;
+ RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
+ GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
+ rect.setStroke(2, iconColor);
+ rect.setColor(bgColor);
+ ImageView transferIcon = headerView.findViewById(
+ com.android.internal.R.id.media_seamless_image);
+ transferIcon.setBackgroundColor(bgColor);
+ transferIcon.setImageTintList(ColorStateList.valueOf(iconColor));
+ TextView transferText = headerView.findViewById(
+ com.android.internal.R.id.media_seamless_text);
+ transferText.setTextColor(iconColor);
+
+ ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
+ transferBackgroundView.setOnClickListener(v -> {
+ final Intent intent = new Intent()
+ .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
+ mActivityStarter.startActivity(intent, false, true /* dismissShade */,
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ });
+
+ // Artist name
+ TextView artistText = mMediaNotifView.findViewById(R.id.header_title);
+ String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ artistText.setText(artistName);
+ artistText.setTextColor(iconColor);
+
+ // Song name
+ TextView titleText = mMediaNotifView.findViewById(R.id.header_text);
+ String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ titleText.setText(songName);
+ titleText.setTextColor(iconColor);
+
+ // Media controls
+ LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
+ final int[] actionIds = {
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4
+ };
+ final int[] notifActionIds = {
+ com.android.internal.R.id.action0,
+ com.android.internal.R.id.action1,
+ com.android.internal.R.id.action2,
+ com.android.internal.R.id.action3,
+ com.android.internal.R.id.action4
+ };
+ for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
+ if (thatBtn == null || thatBtn.getDrawable() == null) {
+ thisBtn.setVisibility(View.GONE);
+ continue;
+ }
+
+ Drawable thatIcon = thatBtn.getDrawable();
+ thisBtn.setImageDrawable(thatIcon.mutate());
+ thisBtn.setVisibility(View.VISIBLE);
+ thisBtn.setOnClickListener(v -> {
+ Log.d(TAG, "clicking on other button");
+ thatBtn.performClick();
+ });
+ }
+ }
+
+ public MediaSession.Token getMediaSessionToken() {
+ return mToken;
+ }
+
+ public String getMediaPlayerPackage() {
+ return mController.getPackageName();
+ }
+
+ /**
+ * Check whether the media controlled by this player is currently playing
+ * @return whether it is playing, or false if no controller information
+ */
+ public boolean isPlaying() {
+ if (mController == null) {
+ return false;
+ }
+
+ PlaybackState state = mController.getPlaybackState();
+ if (state == null) {
+ return false;
+ }
+
+ return (state.getState() == PlaybackState.STATE_PLAYING);
+ }
+
+ private void addAlbumArtBackground(MediaMetadata metadata, int bgColor, int width, int height) {
+ Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ if (albumArt != null) {
+
+ Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
+ Bitmap scaled = scaleBitmap(original, width, height);
+ Canvas canvas = new Canvas(scaled);
+
+ // Add translucent layer over album art to improve contrast
+ Paint p = new Paint();
+ p.setStyle(Paint.Style.FILL);
+ p.setColor(bgColor);
+ p.setAlpha(200);
+ canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), p);
+
+ RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
+ mContext.getResources(), scaled);
+ roundedDrawable.setCornerRadius(20);
+
+ mMediaNotifView.setBackground(roundedDrawable);
+ } else {
+ Log.e(TAG, "No album art available");
+ }
+ }
+
+ private Bitmap scaleBitmap(Bitmap original, int width, int height) {
+ Bitmap cropped = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(cropped);
+
+ float scale = (float) cropped.getWidth() / (float) original.getWidth();
+ float dy = (cropped.getHeight() - original.getHeight() * scale) / 2.0f;
+ Matrix transformation = new Matrix();
+ transformation.postTranslate(0, dy);
+ transformation.preScale(scale, scale);
+
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ canvas.drawBitmap(original, transformation, paint);
+
+ return cropped;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2e24403d460f..20600596c3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -24,16 +24,22 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.service.quicksettings.Tile;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
@@ -82,6 +88,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final QSTileRevealController mQsTileRevealController;
+ private final LinearLayout mMediaCarousel;
+ private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>();
+
protected boolean mExpanded;
protected boolean mListening;
@@ -140,6 +149,27 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
addDivider();
+ // Add media carousel
+ int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
+ if (flag == 1) {
+ HorizontalScrollView mediaScrollView = new HorizontalScrollView(mContext);
+ mediaScrollView.setHorizontalScrollBarEnabled(false);
+ int playerHeight = (int) getResources().getDimension(R.dimen.qs_media_height);
+ int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
+ LayoutParams lpView = new LayoutParams(LayoutParams.MATCH_PARENT, playerHeight);
+ lpView.setMarginStart(padding);
+ lpView.setMarginEnd(padding);
+ addView(mediaScrollView, lpView);
+
+ LayoutParams lpCarousel = new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT);
+ mMediaCarousel = new LinearLayout(mContext);
+ mMediaCarousel.setOrientation(LinearLayout.HORIZONTAL);
+ mediaScrollView.addView(mMediaCarousel, lpCarousel);
+ } else {
+ mMediaCarousel = null;
+ }
+
mFooter = new QSSecurityFooter(this, context);
addView(mFooter.getView());
@@ -159,6 +189,72 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
+ /**
+ * Add or update a player for the associated media session
+ * @param token
+ * @param icon
+ * @param iconColor
+ * @param bgColor
+ * @param actionsContainer
+ * @param notif
+ */
+ public void addMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
+ View actionsContainer, StatusBarNotification notif) {
+ int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
+ if (flag != 1) {
+ // Shouldn't happen, but just in case
+ Log.e(TAG, "Tried to add media session without player!");
+ return;
+ }
+ QSMediaPlayer player = null;
+ String packageName = notif.getPackageName();
+ for (QSMediaPlayer p : mMediaPlayers) {
+ if (p.getMediaSessionToken().equals(token)) {
+ Log.d(TAG, "a player for this session already exists");
+ player = p;
+ break;
+ }
+
+ if (packageName.equals(p.getMediaPlayerPackage())) {
+ Log.d(TAG, "found an old session for this app");
+ player = p;
+ break;
+ }
+ }
+
+ int playerHeight = (int) getResources().getDimension(R.dimen.qs_media_height);
+ int playerWidth = (int) getResources().getDimension(R.dimen.qs_media_width);
+ int padding = (int) getResources().getDimension(R.dimen.qs_media_padding);
+ LayoutParams lp = new LayoutParams(playerWidth, ViewGroup.LayoutParams.MATCH_PARENT);
+ lp.setMarginStart(padding);
+ lp.setMarginEnd(padding);
+
+ if (player == null) {
+ Log.d(TAG, "creating new player");
+
+ player = new QSMediaPlayer(mContext, this, playerWidth, playerHeight);
+
+ if (player.isPlaying()) {
+ mMediaCarousel.addView(player.getView(), 0, lp); // add in front
+ } else {
+ mMediaCarousel.addView(player.getView(), lp); // add at end
+ }
+ } else if (player.isPlaying()) {
+ // move it to the front
+ mMediaCarousel.removeView(player.getView());
+ mMediaCarousel.addView(player.getView(), 0, lp);
+ }
+
+ Log.d(TAG, "setting player session");
+ player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
+ notif.getNotification());
+ mMediaPlayers.add(player);
+ }
+
+ protected View getMediaPanel() {
+ return mMediaCarousel;
+ }
+
protected void addDivider() {
mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 1e763cf79240..b395c3c336d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -30,11 +30,12 @@ import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
-import com.android.systemui.Dependency;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -61,7 +62,6 @@ import java.util.List;
import java.util.function.Predicate;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
@@ -94,8 +94,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
public QSTileHost(Context context,
StatusBarIconController iconController,
QSFactoryImpl defaultFactory,
- @Named(Dependency.MAIN_HANDLER_NAME) Handler mainHandler,
- @Named(Dependency.BG_LOOPER_NAME) Looper bgLooper,
+ @MainHandler Handler mainHandler,
+ @BgLooper Looper bgLooper,
PluginManager pluginManager,
TunerService tunerService,
Provider<AutoTileManager> autoTiles,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
new file mode 100644
index 000000000000..ae66cd576765
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -0,0 +1,203 @@
+/*
+ * 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.qs;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.systemui.R;
+
+/**
+ * QQS mini media player
+ */
+public class QuickQSMediaPlayer {
+
+ private static final String TAG = "QQSMediaPlayer";
+
+ private Context mContext;
+ private LinearLayout mMediaNotifView;
+ private MediaSession.Token mToken;
+ private MediaController mController;
+
+ /**
+ *
+ * @param context
+ * @param parent
+ */
+ public QuickQSMediaPlayer(Context context, ViewGroup parent) {
+ mContext = context;
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mMediaNotifView = (LinearLayout) inflater.inflate(R.layout.qqs_media_panel, parent, false);
+ }
+
+ public View getView() {
+ return mMediaNotifView;
+ }
+
+ /**
+ *
+ * @param token token for this media session
+ * @param icon app notification icon
+ * @param iconColor foreground color (for text, icons)
+ * @param bgColor background color
+ * @param actionsContainer a LinearLayout containing the media action buttons
+ */
+ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
+ View actionsContainer) {
+ Log.d(TAG, "Setting media session: " + token);
+ mToken = token;
+ mController = new MediaController(mContext, token);
+ MediaMetadata mMediaMetadata = mController.getMetadata();
+
+ // Album art
+ addAlbumArtBackground(mMediaMetadata, bgColor);
+
+ // App icon
+ ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
+ Drawable iconDrawable = icon.loadDrawable(mContext);
+ iconDrawable.setTint(iconColor);
+ appIcon.setImageDrawable(iconDrawable);
+
+ // Artist name
+ TextView appText = mMediaNotifView.findViewById(R.id.header_title);
+ String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+ appText.setText(artistName);
+ appText.setTextColor(iconColor);
+
+ // Song name
+ TextView titleText = mMediaNotifView.findViewById(R.id.header_text);
+ String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ titleText.setText(songName);
+ titleText.setTextColor(iconColor);
+
+ // Action buttons
+ LinearLayout parentActionsLayout = (LinearLayout) actionsContainer;
+ final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
+
+ // TODO some apps choose different buttons to show in compact mode
+ final int[] notifActionIds = {
+ com.android.internal.R.id.action1,
+ com.android.internal.R.id.action2,
+ com.android.internal.R.id.action3
+ };
+ for (int i = 0; i < parentActionsLayout.getChildCount() && i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ ImageButton thatBtn = parentActionsLayout.findViewById(notifActionIds[i]);
+ if (thatBtn == null || thatBtn.getDrawable() == null) {
+ thisBtn.setVisibility(View.GONE);
+ continue;
+ }
+
+ Drawable thatIcon = thatBtn.getDrawable();
+ thisBtn.setImageDrawable(thatIcon.mutate());
+ thisBtn.setVisibility(View.VISIBLE);
+
+ thisBtn.setOnClickListener(v -> {
+ Log.d(TAG, "clicking on other button");
+ thatBtn.performClick();
+ });
+ }
+ }
+
+ public MediaSession.Token getMediaSessionToken() {
+ return mToken;
+ }
+
+ /**
+ * Check whether the media controlled by this player is currently playing
+ * @return whether it is playing, or false if no controller information
+ */
+ public boolean isPlaying() {
+ if (mController == null) {
+ return false;
+ }
+
+ PlaybackState state = mController.getPlaybackState();
+ if (state == null) {
+ return false;
+ }
+
+ return (state.getState() == PlaybackState.STATE_PLAYING);
+ }
+
+ private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) {
+ Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ if (albumArt != null) {
+ Rect bounds = new Rect();
+ mMediaNotifView.getBoundsOnScreen(bounds);
+ int width = bounds.width();
+ int height = bounds.height();
+
+ Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
+ Bitmap scaled = scaleBitmap(original, width, height);
+ Canvas canvas = new Canvas(scaled);
+
+ // Add translucent layer over album art to improve contrast
+ Paint p = new Paint();
+ p.setStyle(Paint.Style.FILL);
+ p.setColor(bgColor);
+ p.setAlpha(200);
+ canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), p);
+
+ RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
+ mContext.getResources(), scaled);
+ roundedDrawable.setCornerRadius(20);
+
+ mMediaNotifView.setBackground(roundedDrawable);
+ } else {
+ Log.e(TAG, "No album art available");
+ }
+ }
+
+ private Bitmap scaleBitmap(Bitmap original, int width, int height) {
+ Bitmap cropped = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(cropped);
+
+ float scale = (float) cropped.getWidth() / (float) original.getWidth();
+ float dy = (cropped.getHeight() - original.getHeight() * scale) / 2.0f;
+ Matrix transformation = new Matrix();
+ transformation.postTranslate(0, dy);
+ transformation.preScale(scale, scale);
+
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ canvas.drawBitmap(original, transformation, paint);
+
+ return cropped;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 85aafa06961a..dcd4633a79d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -21,6 +21,7 @@ import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEX
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -55,6 +56,7 @@ public class QuickQSPanel extends QSPanel {
private boolean mDisabledByPolicy;
private int mMaxTiles;
protected QSPanel mFullPanel;
+ private QuickQSMediaPlayer mMediaPlayer;
@Inject
public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -69,11 +71,43 @@ public class QuickQSPanel extends QSPanel {
}
removeView((View) mTileLayout);
}
- sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
- mTileLayout = new HeaderTileLayout(context);
- mTileLayout.setListening(mListening);
- addView((View) mTileLayout, 0 /* Between brightness and footer */);
- super.setPadding(0, 0, 0, 0);
+
+ int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
+ if (flag == 1) {
+ LinearLayout mHorizontalLinearLayout = new LinearLayout(mContext);
+ mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mHorizontalLinearLayout.setClipChildren(false);
+ mHorizontalLinearLayout.setClipToPadding(false);
+
+ LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
+
+ mTileLayout = new DoubleLineTileLayout(context);
+ lp.setMarginEnd(10);
+ lp.setMarginStart(0);
+ mHorizontalLinearLayout.addView((View) mTileLayout, lp);
+
+ mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout);
+
+ lp.setMarginEnd(0);
+ lp.setMarginStart(10);
+ mHorizontalLinearLayout.addView(mMediaPlayer.getView(), lp);
+
+ sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+
+ mTileLayout.setListening(mListening);
+ addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
+ super.setPadding(0, 0, 0, 0);
+ } else {
+ sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+ mTileLayout = new HeaderTileLayout(context);
+ mTileLayout.setListening(mListening);
+ addView((View) mTileLayout, 0 /* Between brightness and footer */);
+ super.setPadding(0, 0, 0, 0);
+ }
+ }
+
+ public QuickQSMediaPlayer getMediaPlayer() {
+ return mMediaPlayer;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 4013586d4197..592e3881ea97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -392,9 +392,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+
+ int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
if (mQsDisabled) {
lp.height = resources.getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
+ } else if (flag == 1) {
+ lp.height = Math.max(getMinimumHeight(),
+ resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_total_height_with_media));
} else {
lp.height = Math.max(getMinimumHeight(),
resources.getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 0679595cef23..341c49a87156 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -16,18 +16,17 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.Dependency.BG_HANDLER_NAME;
-
import android.annotation.NonNull;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+
import java.util.Map;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -50,8 +49,7 @@ public class FeatureFlags {
private final Map<String, Boolean> mCachedDeviceConfigFlags = new ArrayMap<>();
@Inject
- public FeatureFlags(
- @Named(BG_HANDLER_NAME) Handler bgHandler) {
+ public FeatureFlags(@BgHandler Handler bgHandler) {
DeviceConfig.addOnPropertiesChangedListener(
"systemui",
new HandlerExecutor(bgHandler),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 275475d6d72c..1f389049f423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
import static com.android.systemui.SysUiServiceProvider.getComponent;
import android.content.Context;
@@ -38,6 +37,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.systemui.Dependency;
import com.android.systemui.assist.AssistHandleViewController;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -48,7 +48,6 @@ import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.policy.BatteryController;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
@@ -67,7 +66,7 @@ public class NavigationBarController implements Callbacks {
SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
@Inject
- public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+ public NavigationBarController(Context context, @MainHandler Handler handler) {
mContext = context;
mHandler = handler;
mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 23968d59d58f..c838ac5315a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -17,8 +17,6 @@ package com.android.systemui.statusbar;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -52,6 +50,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -69,7 +68,6 @@ import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Lazy;
@@ -262,7 +260,7 @@ public class NotificationRemoteInputManager implements Dumpable {
NotificationEntryManager notificationEntryManager,
Lazy<ShadeController> shadeController,
StatusBarStateController statusBarStateController,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ @MainHandler Handler mainHandler) {
mContext = context;
mLockscreenUserManager = lockscreenUserManager;
mSmartReplyController = smartReplyController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index c2bb5b7693c2..d6b87afc53b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -16,19 +16,19 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -47,7 +47,6 @@ import java.util.List;
import java.util.Stack;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Lazy;
@@ -88,6 +87,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private final BubbleController mBubbleController;
private final DynamicPrivacyController mDynamicPrivacyController;
private final KeyguardBypassController mBypassController;
+ private final Context mContext;
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
@@ -99,8 +99,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private boolean mIsHandleDynamicPrivacyChangeScheduled;
@Inject
- public NotificationViewHierarchyManager(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler,
+ public NotificationViewHierarchyManager(Context context, @MainHandler Handler mainHandler,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManager groupManager,
VisualStabilityManager visualStabilityManager,
@@ -110,6 +109,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
KeyguardBypassController bypassController,
BubbleController bubbleController,
DynamicPrivacyController privacyController) {
+ mContext = context;
mHandler = mainHandler;
mLockscreenUserManager = notificationLockscreenUserManager;
mBypassController = bypassController;
@@ -146,7 +146,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
NotificationEntry ent = activeNotifications.get(i);
+ int flag = Settings.System.getInt(mContext.getContentResolver(),
+ "qs_media_player", 0);
+ boolean hideMedia = (flag == 1);
if (ent.isRowDismissed() || ent.isRowRemoved()
+ || (ent.isMediaNotification() && hideMedia)
|| mBubbleController.isBubbleNotificationSuppressedFromShade(ent.getKey())) {
// we don't want to update removed notifications because they could
// temporarily become children if they were isolated before.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 6fe4abee6133..1daf48492ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
@@ -25,6 +23,7 @@ import android.view.View;
import androidx.collection.ArraySet;
import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -35,7 +34,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -64,8 +62,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
@Inject
public VisualStabilityManager(
- NotificationEntryManager notificationEntryManager,
- @Named(MAIN_HANDLER_NAME) Handler handler) {
+ NotificationEntryManager notificationEntryManager, @MainHandler Handler handler) {
mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 5d5c09e98f11..9bc0ca440893 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -28,6 +28,7 @@ import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.metrics.LogMaker;
import android.os.Handler;
+import android.provider.Settings;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -41,9 +42,12 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.MediaNotificationView;
import com.android.systemui.Dependency;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.util.Timer;
import java.util.TimerTask;
@@ -178,6 +182,26 @@ public class NotificationMediaTemplateViewWrapper extends NotificationTemplateVi
final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
.getParcelable(Notification.EXTRA_MEDIA_SESSION);
+ int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
+ if (flag == 1) {
+ StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
+ QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
+ com.android.systemui.R.id.quick_qs_panel);
+ panel.getMediaPlayer().setMediaSession(token,
+ mRow.getStatusBarNotification().getNotification().getSmallIcon(),
+ getNotificationHeader().getOriginalIconColor(),
+ mRow.getCurrentBackgroundTint(),
+ mActions);
+ QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
+ com.android.systemui.R.id.quick_settings_panel);
+ bigPanel.addMediaSession(token,
+ mRow.getStatusBarNotification().getNotification().getSmallIcon(),
+ getNotificationHeader().getOriginalIconColor(),
+ mRow.getCurrentBackgroundTint(),
+ mActions,
+ mRow.getStatusBarNotification());
+ }
+
boolean showCompactSeekbar = mMediaManager.getShowCompactMediaSeekbar();
if (token == null || (COMPACT_MEDIA_TAG.equals(mView.getTag()) && !showCompactSeekbar)) {
if (mSeekBarView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index 008464e543a0..f9b936763308 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
@@ -25,10 +23,10 @@ import android.util.Log;
import android.view.IWindowManager;
import android.view.MotionEvent;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import javax.inject.Inject;
-import javax.inject.Named;
/** A controller to control all auto-hide things. */
public class AutoHideController {
@@ -54,7 +52,7 @@ public class AutoHideController {
};
@Inject
- public AutoHideController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler,
+ public AutoHideController(Context context, @MainHandler Handler handler,
NotificationRemoteInputManager notificationRemoteInputManager,
IWindowManager iWindowManager) {
mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 007c50c8765d..837517e2cc9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -21,7 +21,7 @@ import android.os.Handler;
import android.provider.Settings.Secure;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
+import com.android.systemui.dagger.qualifiers.BgHandler;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
@@ -33,7 +33,6 @@ import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
import javax.inject.Inject;
-import javax.inject.Named;
/**
* Manages which tiles should be automatically added to QS.
@@ -58,7 +57,7 @@ public class AutoTileManager {
@Inject
public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
- @Named(Dependency.BG_HANDLER_NAME) Handler handler,
+ @BgHandler Handler handler,
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 28dac87c92cf..50d33a70fed5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -25,8 +25,8 @@ import android.provider.Settings;
import android.util.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.DependencyProvider;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainResources;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.tuner.TunerService;
@@ -59,7 +59,7 @@ public class DozeParameters implements TunerService.Tunable,
@Inject
protected DozeParameters(
- @DependencyProvider.MainResources Resources resources,
+ @MainResources Resources resources,
AmbientDisplayConfiguration ambientDisplayConfiguration,
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
PowerManager powerManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index c9c38a0ef5f5..1c8e832d03d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -54,9 +54,7 @@ import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
@@ -70,15 +68,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
"gestures.back_timeout", 250);
- private final PinnedStackListener mImeChangedListener = new PinnedStackListener() {
- @Override
- public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- // No need to thread jump, assignments are atomic
- mImeHeight = imeVisible ? imeHeight : 0;
- // TODO: Probably cancel any existing gesture
- }
- };
-
private ISystemGestureExclusionListener mGestureExclusionListener =
new ISystemGestureExclusionListener.Stub() {
@Override
@@ -126,8 +115,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
private boolean mInRejectedExclusion = false;
private boolean mIsOnLeftEdge;
- private int mImeHeight = 0;
-
private boolean mIsAttached;
private boolean mIsGesturalModeEnabled;
private boolean mIsEnabled;
@@ -227,7 +214,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
}
if (!mIsEnabled) {
- WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener);
mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
try {
@@ -244,7 +230,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
mContext.getMainThreadHandler());
try {
- WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener);
WindowManagerGlobal.getWindowManagerService()
.registerSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
@@ -301,11 +286,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
}
private boolean isWithinTouchRegion(int x, int y) {
- // Disallow if over the IME
- if (y > (mDisplaySize.y - Math.max(mImeHeight, mNavBarHeight))) {
- return false;
- }
-
// Disallow if too far from the edge
if (x > mEdgeWidth + mLeftInset && x < (mDisplaySize.x - mEdgeWidth - mRightInset)) {
return false;
@@ -483,7 +463,6 @@ public class EdgeBackGestureHandler implements DisplayListener {
pw.println(" mInRejectedExclusion" + mInRejectedExclusion);
pw.println(" mExcludeRegion=" + mExcludeRegion);
pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion);
- pw.println(" mImeHeight=" + mImeHeight);
pw.println(" mIsAttached=" + mIsAttached);
pw.println(" mEdgeWidth=" + mEdgeWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 89051cda15ab..30fe68a28ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -770,6 +770,11 @@ public class NotificationPanelView extends PanelView implements
int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings);
int topMargin =
res.getDimensionPixelOffset(com.android.internal.R.dimen.quick_qs_total_height);
+ int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
+ if (flag == 1) {
+ topMargin = res.getDimensionPixelOffset(
+ com.android.internal.R.dimen.quick_qs_total_height_with_media);
+ }
lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams();
if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin
|| lp.rightMargin != sideMargin || lp.topMargin != topMargin) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c50b1bf2dc20..6064fbedf63d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -42,10 +42,10 @@ import com.android.internal.util.function.TriConsumer;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.DejankUtils;
-import com.android.systemui.DependencyProvider;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.dagger.qualifiers.MainResources;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -188,7 +188,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
@Inject
public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
- @DependencyProvider.MainResources Resources resources,
+ @MainResources Resources resources,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index e059715986dc..13055ffb2f77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -39,15 +39,20 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
mFrontTint = Color.BLACK;
- mBehindTint = previousState.mBehindTint;
+ mBehindTint = Color.BLACK;
mBubbleTint = previousState.mBubbleTint;
mFrontAlpha = 1f;
- mBehindAlpha = previousState.mBehindAlpha;
+ mBehindAlpha = 1f;
mBubbleAlpha = previousState.mBubbleAlpha;
mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
}
+
+ @Override
+ public boolean isLowPowerState() {
+ return true;
+ }
},
/**
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 2963c9469fb2..97e09dccdc41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4323,13 +4323,21 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
- if (onDisplayOffCallback != null) {
+ if (mPendingScreenOffCallback != null) {
Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one.");
}
mPendingScreenOffCallback = onDisplayOffCallback;
updateScrimController();
}
+ @Override
+ public void cancelGentleSleep() {
+ mPendingScreenOffCallback = null;
+ if (mScrimController.getState() == ScrimState.OFF) {
+ updateScrimController();
+ }
+ }
+
/**
* When the dozing host is waiting for scrims to fade out to change the display state.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 0a2fb2e783a9..76683b6a5e6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
-
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
@@ -36,6 +33,8 @@ import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.systemui.dagger.qualifiers.BgLooper;
+import com.android.systemui.dagger.qualifiers.MainLooper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -46,7 +45,6 @@ import java.util.List;
import java.util.WeakHashMap;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -74,9 +72,8 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
/**
*/
@Inject
- public BluetoothControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
- @Named(MAIN_LOOPER_NAME) Looper mainLooper,
- @Nullable LocalBluetoothManager localBluetoothManager) {
+ public BluetoothControllerImpl(Context context, @BgLooper Looper bgLooper,
+ @MainLooper Looper mainLooper, @Nullable LocalBluetoothManager localBluetoothManager) {
mLocalBluetoothManager = localBluetoothManager;
mBgHandler = new Handler(bgLooper);
mHandler = new H(mainLooper);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index 089d5c924de8..0a40b3c4831c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -14,8 +14,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -26,12 +24,12 @@ import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.util.Log;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.settings.CurrentUserTracker;
import java.util.ArrayList;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -51,8 +49,7 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen
/**
*/
@Inject
- public DeviceProvisionedControllerImpl(Context context,
- @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ public DeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler) {
super(context);
mContext = context;
mContentResolver = context.getContentResolver();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 1c6d12f15e4c..8f201c793258 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -26,12 +24,13 @@ import android.os.Handler;
import android.os.UserManager;
import android.util.Log;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -56,7 +55,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
/**
*/
@Inject
- public HotspotControllerImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ public HotspotControllerImpl(Context context, @MainHandler Handler mainHandler) {
mContext = context;
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 683cdbb326dc..5a97eedd9b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy;
import static com.android.settingslib.Utils.updateLocationEnabled;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@@ -36,13 +35,13 @@ import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.BgLooper;
import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -66,7 +65,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
private final H mHandler = new H();
@Inject
- public LocationControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper) {
+ public LocationControllerImpl(Context context, @BgLooper Looper bgLooper) {
mContext = context;
// Register to listen for changes in location settings.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 7b5d48947498..60784c91ee62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -24,7 +24,6 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OU
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -65,6 +64,7 @@ import com.android.systemui.ConfigurationChangedReceiver;
import com.android.systemui.DemoMode;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.BgLooper;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
@@ -81,7 +81,6 @@ import java.util.Locale;
import java.util.Map;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/** Platform implementation of the network controller. **/
@@ -170,7 +169,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
* Construct this controller object and register for updates.
*/
@Inject
- public NetworkControllerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
+ public NetworkControllerImpl(Context context, @BgLooper Looper bgLooper,
DeviceProvisionedController deviceProvisionedController) {
this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index d88ae78c5afb..6edd75b20fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.BG_HANDLER_NAME;
-
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -50,6 +48,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.BgHandler;
import com.android.systemui.settings.CurrentUserTracker;
import java.io.FileDescriptor;
@@ -57,7 +56,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -102,7 +100,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
/**
*/
@Inject
- public SecurityControllerImpl(Context context, @Named(BG_HANDLER_NAME) Handler bgHandler) {
+ public SecurityControllerImpl(Context context, @BgHandler Handler bgHandler) {
this(context, bgHandler, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index 655c29cbf687..347d3009c3ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.app.RemoteInput;
import android.content.Context;
import android.content.res.Resources;
@@ -30,9 +28,9 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
@Singleton
@@ -67,7 +65,7 @@ public final class SmartReplyConstants {
private final KeyValueListParser mParser = new KeyValueListParser(',');
@Inject
- public SmartReplyConstants(@Named(MAIN_HANDLER_NAME) Handler handler, Context context) {
+ public SmartReplyConstants(@MainHandler Handler handler, Context context) {
mHandler = handler;
mContext = context;
final Resources resources = mContext.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index bcfbdacf9ea8..f2d2faed6a42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -58,6 +57,7 @@ import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.tiles.UserDetailView;
@@ -70,7 +70,6 @@ import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -110,7 +109,7 @@ public class UserSwitcherController implements Dumpable {
@Inject
public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
- @Named(MAIN_HANDLER_NAME) Handler handler, ActivityStarter activityStarter) {
+ @MainHandler Handler handler, ActivityStarter activityStarter) {
mContext = context;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(context);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 29c42d24b3b4..1c7a1951b27d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.policy;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
@@ -41,6 +39,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.util.Utils;
@@ -51,7 +50,6 @@ import java.util.ArrayList;
import java.util.Objects;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/** Platform implementation of the zen mode controller. **/
@@ -79,7 +77,7 @@ public class ZenModeControllerImpl extends CurrentUserTracker
private NotificationManager.Policy mConsolidatedNotificationPolicy;
@Inject
- public ZenModeControllerImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+ public ZenModeControllerImpl(Context context, @MainHandler Handler handler) {
super(context);
mContext = context;
mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index a55e2cf38e39..2d6027cb324d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui.tuner;
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -36,6 +34,7 @@ import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
import com.android.systemui.DejankUtils;
import com.android.systemui.DemoMode;
+import com.android.systemui.dagger.qualifiers.MainHandler;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -46,7 +45,6 @@ import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
@@ -83,7 +81,7 @@ public class TunerServiceImpl extends TunerService {
/**
*/
@Inject
- public TunerServiceImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler,
+ public TunerServiceImpl(Context context, @MainHandler Handler mainHandler,
LeakDetector leakDetector) {
mContext = context;
mContentResolver = mContext.getContentResolver();
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 7e801da9cd1b..5ed027d37def 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,7 +26,7 @@ import android.view.View;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
-import com.android.systemui.SystemUIRootComponent;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.qs.QSCarrierGroup;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index 63db755ef09d..bff405c0bee6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -20,7 +20,6 @@ import static android.service.quicksettings.Tile.STATE_ACTIVE;
import static android.telephony.ims.feature.ImsFeature.STATE_UNAVAILABLE;
import static com.android.internal.logging.MetricsLogger.VIEW_UNKNOWN;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -48,6 +47,7 @@ import android.util.LongSparseArray;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.qualifiers.BgLooper;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSHost;
@@ -59,7 +59,6 @@ import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
-import javax.inject.Named;
import javax.inject.Singleton;
/**
@@ -110,7 +109,7 @@ public class GarbageMonitor implements Dumpable {
@Inject
public GarbageMonitor(
Context context,
- @Named(BG_LOOPER_NAME) Looper bgLooper,
+ @BgLooper Looper bgLooper,
LeakDetector leakDetector,
LeakReporter leakReporter) {
mContext = context.getApplicationContext();
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index fdffc4338843..a96977a338a9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -25,8 +25,8 @@ import android.os.Handler;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.DependencyProvider;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.MainResources;
import java.util.ArrayList;
import java.util.List;
@@ -65,7 +65,7 @@ public class ProximitySensor {
};
@Inject
- public ProximitySensor(@DependencyProvider.MainResources Resources resources,
+ public ProximitySensor(@MainResources Resources resources,
AsyncSensorManager sensorManager) {
mSensorManager = sensorManager;
Sensor sensor = findBrightnessSensor(resources);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1b132b962493..85c247e11f94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -64,6 +64,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@@ -249,7 +250,7 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(OPAQUE /* front */,
- SEMI_TRANSPARENT /* back */,
+ OPAQUE /* back */,
TRANSPARENT /* bubble */);
assertScrimTint(true /* front */,
@@ -858,6 +859,22 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimForBubble.getDefaultFocusHighlightEnabled());
}
+ @Test
+ public void testIsLowPowerMode() {
+ HashSet<ScrimState> lowPowerModeStates = new HashSet<>(Arrays.asList(
+ ScrimState.OFF, ScrimState.AOD, ScrimState.PULSING));
+ HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
+ ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
+ ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
+ ScrimState.BUBBLE_EXPANDED));
+
+ for (ScrimState state : ScrimState.values()) {
+ if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
+ Assert.fail("Scrim state not whitelisted nor blacklisted as low power mode");
+ }
+ }
+ }
+
private void assertScrimTint(boolean front, boolean behind, boolean bubble) {
Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
+ " with scrim: " + getScrimName(mScrimInFront) + " and tint: "
diff --git a/services/art-profile b/services/art-profile
index 8b911a24b5cc..a0338d55c55f 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -21148,7 +21148,6 @@ HPLcom/android/server/wm/RemoteAnimationController$FinishedCallback;->release()V
HPLcom/android/server/wm/RemoteAnimationController;->lambda$goodToGo$1$RemoteAnimationController([Landroid/view/RemoteAnimationTarget;[Landroid/view/RemoteAnimationTarget;)V
HPLcom/android/server/wm/RunningTasks;->getTasks(ILjava/util/List;IILjava/util/ArrayList;IZZLandroid/util/ArraySet;)V
HPLcom/android/server/wm/SplashScreenStartingData;->createStartingSurface(Lcom/android/server/wm/ActivityRecord;)Lcom/android/server/policy/WindowManagerPolicy$StartingSurface;
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
HPLcom/android/server/wm/SurfaceAnimator;->lambda$getFinishedCallback$0$SurfaceAnimator(Lcom/android/server/wm/AnimationAdapter;Ljava/lang/Runnable;)V
HPLcom/android/server/wm/Task;->positionChildAt(ILcom/android/server/wm/ActivityRecord;Z)V
HPLcom/android/server/wm/TaskRecord;->handlesOrientationChangeFromDescendant()Z
@@ -21191,7 +21190,6 @@ HPLcom/android/server/wm/DisplayRotation;->updateRotationUnchecked(Z)Z
HPLcom/android/server/wm/RemoteAnimationController;->createRemoteAnimationRecord(Lcom/android/server/wm/ActivityRecord;Landroid/graphics/Point;Landroid/graphics/Rect;Landroid/graphics/Rect;)Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationRecord;
HPLcom/android/server/wm/RemoteAnimationController;->linkToDeathOfRunner()V
HPLcom/android/server/wm/RemoteAnimationController;->writeStartDebugStatement()V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
HPLcom/android/server/wm/TaskRecord;->setMinDimensions(Landroid/content/pm/ActivityInfo;)V
HPLcom/android/server/wm/WallpaperAnimationAdapter;->startWallpaperAnimations(Lcom/android/server/wm/WindowManagerService;JJLjava/util/function/Consumer;Ljava/util/ArrayList;)[Landroid/view/RemoteAnimationTarget;
HPLcom/android/server/wm/WindowStateAnimator;->finishDrawingLocked(Landroid/view/SurfaceControl$Transaction;)Z
@@ -21206,13 +21204,152 @@ HPLcom/android/server/statusbar/StatusBarManagerService;->setSystemUiVisibility(
HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->dump(Ljava/io/PrintWriter;Ljava/lang/String;)V
HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationRecord;-><init>(Lcom/android/server/wm/RemoteAnimationController;Lcom/android/server/wm/ActivityRecord;Landroid/graphics/Point;Landroid/graphics/Rect;Landroid/graphics/Rect;)V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
HPLcom/android/server/wm/WindowProcessController;->setBoundClientUids(Landroid/util/ArraySet;)V
HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onActivityLaunched$2$IorapForwardingService$AppLaunchObserver([BILcom/google/android/startop/iorap/IIorap;)V
HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onActivityLaunchFinished$4$IorapForwardingService$AppLaunchObserver([BJLcom/google/android/startop/iorap/IIorap;)V
HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onIntentStarted$0$IorapForwardingService$AppLaunchObserver(Landroid/content/Intent;JLcom/google/android/startop/iorap/IIorap;)V
HPLcom/android/server/statusbar/StatusBarManagerService;->updateUiVisibilityLocked(IIIIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)V
HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
HPLcom/google/android/startop/iorap/IIorap$Stub$Proxy;->onAppLaunchEvent(Lcom/google/android/startop/iorap/RequestId;Lcom/google/android/startop/iorap/AppLaunchEvent;)V
HPLcom/google/android/startop/iorap/RequestId;->nextValueForSequence()Lcom/google/android/startop/iorap/RequestId;
+HPLcom/android/server/AlarmManagerService;->decrementAlarmCount(II)V
+HPLcom/android/server/am/ActivityManagerService$4;->newArray(I)[Landroid/content/IntentFilter;
+HPLcom/android/server/am/ActivityManagerService$PidMap;->remove(Lcom/android/server/am/ProcessRecord;)V
+HPLcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Ljava/lang/String;)V
+HPLcom/android/server/am/ActivityManagerShellCommand$1;-><init>(Lcom/android/server/am/ActivityManagerShellCommand;)V
+HPLcom/android/server/am/ActivityManagerShellCommand;-><init>(Lcom/android/server/am/ActivityManagerService;Z)V
+HPLcom/android/server/am/ActivityManagerShellCommand;->runStartActivity(Ljava/io/PrintWriter;)I
+HPLcom/android/server/am/HostingRecord;-><init>(Ljava/lang/String;Landroid/content/ComponentName;I)V
+HPLcom/android/server/am/PendingIntentController;->registerIntentSenderCancelListener(Landroid/content/IIntentSender;Lcom/android/internal/os/IResultReceiver;)V
+HPLcom/android/server/appprediction/-$$Lambda$AppPredictionManagerService$PredictionManagerServiceStub$vSY20eQq5y5FXrxhhqOTcEmezTs;-><init>(Landroid/app/prediction/AppPredictionSessionId;)V
+HPLcom/android/server/appprediction/-$$Lambda$RemoteAppPredictionService$9DCowUTEF8fYuBlWGxOmP5hTAWA;-><init>(Landroid/app/prediction/AppPredictionSessionId;)V
+HPLcom/android/server/appprediction/RemoteAppPredictionService;->lambda$requestPredictionUpdate$6(Landroid/app/prediction/AppPredictionSessionId;Landroid/service/appprediction/IPredictionService;)V
+HPLcom/android/server/autofill/-$$Lambda$AutofillManagerService$1$1-WNu3tTkxodB_LsZ7dGIlvrPN0;->visit(Ljava/lang/Object;)V
+HPLcom/android/server/autofill/ui/-$$Lambda$AutoFillUI$56AC3ykfo4h_e2LSjdkJ3XQn370;-><init>(Lcom/android/server/autofill/ui/AutoFillUI;Lcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$Enqw46SYVKFK9F2xX4qUcIu5_3I;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$eoGnQ2MDLLnW1UBX6wxNE1VBLAk;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$VKh1DoMPNSPjPfnVGdsInmxuqzc;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$yUTbcaYlZCYTmagCkNJ3i2VCkY4;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/RemoteContentSuggestionsService;->getServiceInterface(Landroid/os/IBinder;)Landroid/os/IInterface;
+HPLcom/android/server/display/AutomaticBrightnessController;->updateAutoBrightness(ZZ)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->setModifier(I)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->setReason(I)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->toString(I)Ljava/lang/String;
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->toString()Ljava/lang/String;
+HPLcom/android/server/media/projection/MediaProjectionManagerService$1;->onProcessDied(II)V
+HPLcom/android/server/net/NetworkPolicyManagerService;->removeUidStateUL(I)Z
+HPLcom/android/server/pm/permission/PermissionManagerService;->addOnPermissionsChangeListener(Landroid/permission/IOnPermissionsChangeListener;)V
+HPLcom/android/server/protolog/ProtoLogImpl;->getSingleInstance()Lcom/android/server/protolog/ProtoLogImpl;
+HPLcom/android/server/soundtrigger/SoundTriggerHelper$PowerSaveModeListener;-><init>(Lcom/android/server/soundtrigger/SoundTriggerHelper;)V
+HPLcom/android/server/statusbar/-$$Lambda$StatusBarManagerService$uF0ibEnnXe7Lxunxb98QQLJjgZM;->run()V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setSystemUiState(IIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->systemUiStateEquals(IIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)Z
+HPLcom/android/server/usage/UsageStatsDatabase;->filterStats(Lcom/android/server/usage/IntervalStats;)V
+HPLcom/android/server/VibratorService$VibrationInfo;-><init>(JLandroid/os/VibrationEffect;Landroid/os/VibrationEffect;Landroid/media/AudioAttributes;ILjava/lang/String;Ljava/lang/String;)V
+HPLcom/android/server/VibratorService;->getAppOpMode(Lcom/android/server/VibratorService$Vibration;)I
+HPLcom/android/server/VibratorService;->getCurrentIntensityLocked(Lcom/android/server/VibratorService$Vibration;)I
+HPLcom/android/server/VibratorService;->isAllowedToVibrateLocked(Lcom/android/server/VibratorService$Vibration;)Z
+HPLcom/android/server/VibratorService;->vibrate(ILjava/lang/String;Landroid/os/VibrationEffect;Landroid/media/AudioAttributes;Ljava/lang/String;Landroid/os/IBinder;)V
+HPLcom/android/server/wm/-$$Lambda$ActivityRecord$g49I60MBbnNkxHlgA-NR7ALwWTQ;->apply(Ljava/lang/Object;)Z
+HPLcom/android/server/wm/-$$Lambda$ActivityRecord$pBc6yUdDV5IrUd9vt6oCz6QzpiE;->accept(Ljava/lang/Object;)V
+HPLcom/android/server/wm/-$$Lambda$BEx3OWenCvYAaV5h_J2ZkZXhEcY;->accept(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
+HPLcom/android/server/wm/-$$Lambda$DisplayPolicy$Zbxkj4wIhcDki6VwBh1kWmSmxqM;-><init>(Lcom/android/server/wm/DisplayPolicy;IIILandroid/graphics/Rect;Landroid/graphics/Rect;ZLcom/android/server/wm/WindowState;I[Lcom/android/internal/view/AppearanceRegion;ZZ)V
+HPLcom/android/server/wm/-$$Lambda$DisplayPolicy$Zbxkj4wIhcDki6VwBh1kWmSmxqM;->run()V
+HPLcom/android/server/wm/-$$Lambda$TaskChangeNotificationController$UexNbaqPy0mc3VxTw2coCctHho8;->accept(Landroid/app/ITaskStackListener;Landroid/os/Message;)V
+HPLcom/android/server/wm/ActivityMetricsLogger;->allWindowsDrawn()Z
+HPLcom/android/server/wm/ActivityRecord;->createAnimationBoundsLayer(Landroid/view/SurfaceControl$Transaction;)Landroid/view/SurfaceControl;
+HPLcom/android/server/wm/ActivityRecord;->destroyed(Ljava/lang/String;)V
+HPLcom/android/server/wm/ActivityRecord;->forAllWindowsUnchecked(Lcom/android/internal/util/ToBooleanFunction;Z)Z
+HPLcom/android/server/wm/ActivityRecord;->getTopFullscreenWindow()Lcom/android/server/wm/WindowState;
+HPLcom/android/server/wm/ActivityRecord;->loadAnimation(Landroid/view/WindowManager$LayoutParams;IZZ)Landroid/view/animation/Animation;
+HPLcom/android/server/wm/ActivityRecord;->notifyAppStopped()V
+HPLcom/android/server/wm/ActivityRecord;->onFirstWindowDrawn(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowStateAnimator;)V
+HPLcom/android/server/wm/ActivityRecord;->onRemovedFromDisplay()V
+HPLcom/android/server/wm/ActivityRecord;->removeDeadWindows()V
+HPLcom/android/server/wm/ActivityRecord;->setClientHidden(Z)V
+HPLcom/android/server/wm/ActivityRecord;->stopFreezingScreenLocked(Z)V
+HPLcom/android/server/wm/ActivityStack;->removeTimeoutsForActivity(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/ActivityStarter;->recycleTask(Lcom/android/server/wm/TaskRecord;Lcom/android/server/wm/ActivityRecord;Lcom/android/server/wm/ActivityRecord;[Lcom/android/server/wm/ActivityRecord;)I
+HPLcom/android/server/wm/ActivityTaskManagerService;->getTaskSnapshot(IZZ)Landroid/app/ActivityManager$TaskSnapshot;
+HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/DisplayContent;->getWindowCornerRadius()F
+HPLcom/android/server/wm/DisplayPolicy;->convertNonDecorInsetsToStableInsets(Landroid/graphics/Rect;I)V
+HPLcom/android/server/wm/DisplayPolicy;->getInsetsPolicy()Lcom/android/server/wm/InsetsPolicy;
+HPLcom/android/server/wm/DisplayPolicy;->updateLightStatusBarAppearanceLw(ILcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState;)I
+HPLcom/android/server/wm/InsetsPolicy;->getInsetsForDispatch(Lcom/android/server/wm/WindowState;)Landroid/view/InsetsState;
+HPLcom/android/server/wm/InsetsPolicy;->isHidden(I)Z
+HPLcom/android/server/wm/InsetsPolicy;->updateBarControlTarget(Lcom/android/server/wm/WindowState;)V
+HPLcom/android/server/wm/Task;->getTopFullscreenActivity()Lcom/android/server/wm/ActivityRecord;
+HPLcom/android/server/wm/TaskRecord;->removeTaskActivitiesLocked(Ljava/lang/String;)V
+HPLcom/android/server/wm/Task;->removeChild(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/TaskSnapshotCache$CacheEntry;-><init>(Landroid/app/ActivityManager$TaskSnapshot;Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/TaskSnapshotController;->createTaskSnapshot(Lcom/android/server/wm/Task;F)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;
+HPLcom/android/server/wm/TaskSnapshotController;->findAppTokenForSnapshot(Lcom/android/server/wm/Task;)Lcom/android/server/wm/ActivityRecord;
+HPLcom/android/server/wm/TaskSnapshotPersister$DeleteWriteQueueItem;-><init>(Lcom/android/server/wm/TaskSnapshotPersister;II)V
+HPLcom/android/server/wm/TaskSnapshotPersister$StoreWriteQueueItem;-><init>(Lcom/android/server/wm/TaskSnapshotPersister;IILandroid/app/ActivityManager$TaskSnapshot;)V
+HPLcom/android/server/wm/TaskSnapshotPersister$StoreWriteQueueItem;->onQueuedLocked()V
+HPLcom/android/server/wm/WallpaperAnimationAdapter;->lambda$startWallpaperAnimations$0(JJLjava/util/function/Consumer;Ljava/util/ArrayList;Ljava/util/ArrayList;Lcom/android/server/wm/WallpaperWindowToken;)V
+HPLcom/android/server/wm/WallpaperAnimationAdapter;->startWallpaperAnimations(Lcom/android/server/wm/WindowManagerService;JJLjava/util/function/Consumer;Ljava/util/ArrayList;)[Landroid/view/RemoteAnimationTarget;
+HPLcom/android/server/wm/WindowAnimationSpec;->findTranslateAnimation(Landroid/view/animation/Animation;)Landroid/view/animation/TranslateAnimation;
+HPLcom/android/server/wm/WindowProcessControllerMap;->removeProcessFromUidMap(Lcom/android/server/wm/WindowProcessController;)V
+HPLcom/android/server/wm/WindowProcessController;->updateProcessInfo(ZZZ)V
+HPLcom/android/server/wm/WindowState$DeathRecipient;-><init>(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState$1;)V
+HPLcom/android/server/wm/WindowState$WindowId;-><init>(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState$1;)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$ActivityLaunched;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$ActivityLaunchFinished;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$IntentStarted;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent;->getTypeIndex()I
+HPLcom/android/server/pm/PackageManagerService;->access$7600(Lcom/android/server/pm/PackageManagerService;Landroid/content/Intent;Ljava/lang/String;IIZI)Landroid/content/pm/ResolveInfo;
+HPLcom/android/server/pm/PackageManagerService;->access$8100(Lcom/android/server/pm/PackageManagerService;II)Z
+HPLcom/android/server/wm/ActivityRecord$Token;->access$100(Lcom/android/server/wm/ActivityRecord$Token;Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$000(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Lcom/android/server/wm/SurfaceAnimator$OnAnimationFinishedCallback;
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$400(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Landroid/graphics/Point;
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$500(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Landroid/graphics/Rect;
+HPLcom/android/server/wm/RemoteAnimationController;->access$100(Lcom/android/server/wm/RemoteAnimationController;)V
+HPLcom/android/server/wm/RemoteAnimationController;->access$300(Lcom/android/server/wm/RemoteAnimationController;)Landroid/view/RemoteAnimationAdapter;
+HPLcom/android/server/wm/TaskPersister$TaskWriteQueueItem;->access$200(Lcom/android/server/wm/TaskPersister$TaskWriteQueueItem;)Lcom/android/server/wm/TaskRecord;
+HPLcom/android/server/wm/TaskPersister;->access$000(I)Ljava/io/File;
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
+HPLcom/android/server/wm/WindowManagerService;->access$1600(Lcom/android/server/wm/WindowManagerService;Landroid/os/IBinder;)V
+HPLcom/android/server/pm/ShortcutUser;->logSharingShortcutStats(Lcom/android/internal/logging/MetricsLogger;)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->lambda$topAppWindowChanged$1$StatusBarManagerService(IZZ)V
+HPLcom/android/server/wm/ActivityRecord$Token;->attach(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/DisplayPolicy;->lambda$updateSystemUiVisibilityLw$10$DisplayPolicy(IIILandroid/graphics/Rect;Landroid/graphics/Rect;ZLcom/android/server/wm/WindowState;I[Lcom/android/internal/view/AppearanceRegion;ZZ)V
+HPLcom/android/server/wm/InsetsSourceProvider;->hasWindow()Z
+HPLcom/android/server/wm/InsetsStateController;->onBarControlTargetChanged(Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;)V
+HPLcom/android/server/wm/InsetsStateController;->peekSourceProvider(I)Lcom/android/server/wm/InsetsSourceProvider;
+HPLcom/android/server/wm/TaskPersister$TaskWriteQueueItem;->access$200(Lcom/android/server/wm/TaskPersister$TaskWriteQueueItem;)Lcom/android/server/wm/TaskRecord;
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
+HPLcom/android/server/-$$Lambda$AlarmManagerService$2$Eo-D98J-N9R2METkD-12gPs320c;-><init>(Lcom/android/server/AlarmManagerService$2;Landroid/app/IAlarmCompleteListener;)V
+HPLcom/android/server/AlarmManagerService;->access$100(Lcom/android/server/AlarmManagerService;)Lcom/android/server/AlarmManagerService$Injector;
+HPLcom/android/server/AlarmManagerService;->access$2102(Lcom/android/server/AlarmManagerService;J)J
+HPLcom/android/server/AlarmManagerService;->access$2202(Lcom/android/server/AlarmManagerService;J)J
+HPLcom/android/server/AlarmManagerService;->access$2300(Lcom/android/server/AlarmManagerService;)V
+HPLcom/android/server/AlarmManagerService;->access$2400(Lcom/android/server/AlarmManagerService;Lcom/android/server/AlarmManagerService$Alarm;)Z
+HPLcom/android/server/AlarmManagerService;->isExemptFromAppStandby(Lcom/android/server/AlarmManagerService$Alarm;)Z
+HPLcom/android/server/appwidget/AppWidgetServiceImpl$HostId;-><init>(IILjava/lang/String;)V
+HPLcom/android/server/content/ContentService$ObserverCall;->run()V
+HPLcom/android/server/statusbar/-$$Lambda$StatusBarManagerService$uF0ibEnnXe7Lxunxb98QQLJjgZM;-><init>(Lcom/android/server/statusbar/StatusBarManagerService;IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService$1;->topAppWindowChanged(IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->access$1600(Lcom/android/server/statusbar/StatusBarManagerService$UiState;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->access$1700(Lcom/android/server/statusbar/StatusBarManagerService$UiState;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setFullscreen(Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setImmersive(Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->access$600(Lcom/android/server/statusbar/StatusBarManagerService;IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->enforceStatusBar()V
+HPLcom/android/server/statusbar/StatusBarManagerService;->getUiState(I)Lcom/android/server/statusbar/StatusBarManagerService$UiState;
+HPLcom/android/server/statusbar/StatusBarManagerService;->topAppWindowChanged(IZZ)V
+HPLcom/android/server/wm/InsetsStateController;->onControlFakeTargetChanged(ILcom/android/server/wm/InsetsControlTarget;)V
+HPLcom/android/server/wm/LocalAnimationAdapter$AnimationSpec;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/LocalAnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;)V
+HPLcom/android/server/wm/PersisterQueue;->access$100(Lcom/android/server/wm/PersisterQueue;)Ljava/util/ArrayList;
+HPLcom/android/server/wm/PersisterQueue;->access$200(Lcom/android/server/wm/PersisterQueue;)Ljava/util/ArrayList;
+HPLcom/android/server/wm/PersisterQueue;->access$300(Lcom/android/server/wm/PersisterQueue;)V
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$100(Lcom/android/server/wm/TaskSnapshotPersister;)Ljava/lang/Object;
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$200(Lcom/android/server/wm/TaskSnapshotPersister;)Z
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$300(Lcom/android/server/wm/TaskSnapshotPersister;)Ljava/util/ArrayDeque;
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$402(Lcom/android/server/wm/TaskSnapshotPersister;Z)Z
+HPLcom/android/server/wm/WindowAnimationSpec;->findTranslateAnimation(Landroid/view/animation/Animation;)Landroid/view/animation/TranslateAnimation;
+HPLcom/android/server/wm/WindowAnimationSpec;->writeToProtoInner(Landroid/util/proto/ProtoOutputStream;)V
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 7d129eaa5390..1fc47516864b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -197,8 +197,20 @@ final class SaveUi {
if ((type & SaveInfo.SAVE_DATA_TYPE_ADDRESS) != 0) {
types.add(context.getString(R.string.autofill_save_type_address));
}
- if ((type & SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD) != 0) {
+
+ // fallback to generic card type if set multiple types
+ final int cardTypeMask = SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD
+ | SaveInfo.SAVE_DATA_TYPE_DEBIT_CARD
+ | SaveInfo.SAVE_DATA_TYPE_PAYMENT_CARD;
+ final int count = Integer.bitCount(type & cardTypeMask);
+ if (count > 1 || (type & SaveInfo.SAVE_DATA_TYPE_GENERIC_CARD) != 0) {
+ types.add(context.getString(R.string.autofill_save_type_generic_card));
+ } else if ((type & SaveInfo.SAVE_DATA_TYPE_PAYMENT_CARD) != 0) {
+ types.add(context.getString(R.string.autofill_save_type_payment_card));
+ } else if ((type & SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD) != 0) {
types.add(context.getString(R.string.autofill_save_type_credit_card));
+ } else if ((type & SaveInfo.SAVE_DATA_TYPE_DEBIT_CARD) != 0) {
+ types.add(context.getString(R.string.autofill_save_type_debit_card));
}
if ((type & SaveInfo.SAVE_DATA_TYPE_USERNAME) != 0) {
types.add(context.getString(R.string.autofill_save_type_username));
@@ -269,7 +281,9 @@ final class SaveUi {
noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener()));
final TextView yesButton = view.findViewById(R.id.autofill_save_yes);
- if (isUpdate) {
+ if (info.getPositiveActionStyle() == SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE) {
+ yesButton.setText(R.string.autofill_continue_yes);
+ } else if (isUpdate) {
yesButton.setText(R.string.autofill_update_yes);
}
yesButton.setOnClickListener((v) -> mListener.onSave());
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 1d22b824aff9..ad3f5020031d 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1000,6 +1000,12 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void onReportLocation(Location location) {
+ // likelihood of a 0,0 bug is far greater than this being a valid location
+ if (!isMock() && location.getLatitude() == 0 && location.getLongitude() == 0) {
+ Slog.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ return;
+ }
+
synchronized (mLock) {
handleLocationChangedLocked(location, this);
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 854f16aeb54e..9ac9955493cc 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -19,7 +19,7 @@ package com.android.server.compat;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.os.Process;
+import android.os.UserHandle;
import android.util.Slog;
import android.util.StatsLog;
@@ -54,8 +54,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public void reportChangeByPackageName(long changeId, String packageName) {
- ApplicationInfo appInfo = getApplicationInfo(packageName);
+ public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
}
@@ -80,8 +80,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public boolean isChangeEnabledByPackageName(long changeId, String packageName) {
- ApplicationInfo appInfo = getApplicationInfo(packageName);
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
}
@@ -96,7 +96,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
boolean enabled = true;
for (String packageName : packages) {
- enabled = enabled && isChangeEnabledByPackageName(changeId, packageName);
+ enabled = enabled && isChangeEnabledByPackageName(changeId, packageName,
+ UserHandle.getUserId(uid));
}
return enabled;
}
@@ -127,10 +128,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
mChangeReporter.resetReportedChanges(appInfo.uid);
}
- private ApplicationInfo getApplicationInfo(String packageName) {
+ private ApplicationInfo getApplicationInfo(String packageName, int userId) {
try {
- return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0,
- Process.myUid());
+ return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "No installed package " + packageName);
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java
index 839967139baa..85dfbf411667 100644
--- a/services/core/java/com/android/server/compat/PlatformCompatNative.java
+++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java
@@ -29,8 +29,8 @@ public class PlatformCompatNative extends IPlatformCompatNative.Stub {
}
@Override
- public void reportChangeByPackageName(long changeId, String packageName) {
- mPlatformCompat.reportChangeByPackageName(changeId, packageName);
+ public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ mPlatformCompat.reportChangeByPackageName(changeId, packageName, userId);
}
@Override
@@ -39,8 +39,8 @@ public class PlatformCompatNative extends IPlatformCompatNative.Stub {
}
@Override
- public boolean isChangeEnabledByPackageName(long changeId, String packageName) {
- return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName);
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName, userId);
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 34fb64190e8e..9bbe62839db7 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -23,8 +23,11 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
+import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -101,7 +104,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -116,7 +118,6 @@ import com.android.internal.util.Preconditions;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.CredentialType;
import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
@@ -178,7 +179,6 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final int PROFILE_KEY_IV_SIZE = 12;
private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
- private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1;
private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
@@ -317,14 +317,34 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ private LockscreenCredential generateRandomProfilePassword() {
+ byte[] randomLockSeed = new byte[] {};
+ try {
+ randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
+ char[] newPasswordChars = HexEncoding.encode(randomLockSeed);
+ byte[] newPassword = new byte[newPasswordChars.length];
+ for (int i = 0; i < newPasswordChars.length; i++) {
+ newPassword[i] = (byte) newPasswordChars[i];
+ }
+ LockscreenCredential credential =
+ LockscreenCredential.createManagedPassword(newPassword);
+ Arrays.fill(newPasswordChars, '\u0000');
+ Arrays.fill(newPassword, (byte) 0);
+ Arrays.fill(randomLockSeed, (byte) 0);
+ return credential;
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Fail to generate profile password", e);
+ }
+ }
+
/**
* Tie managed profile to primary profile if it is in unified mode and not tied before.
*
* @param managedUserId Managed profile user Id
* @param managedUserPassword Managed profile original password (when it has separated lock).
- * NULL when it does not have a separated lock before.
*/
- public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) {
+ public void tieManagedProfileLockIfNecessary(int managedUserId,
+ LockscreenCredential managedUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
// Only for managed profile
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
@@ -356,27 +376,10 @@ public class LockSettingsService extends ILockSettings.Stub {
return;
}
if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
- byte[] randomLockSeed = new byte[] {};
- try {
- randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
- char[] newPasswordChars = HexEncoding.encode(randomLockSeed);
- byte[] newPassword = new byte[newPasswordChars.length];
- for (int i = 0; i < newPasswordChars.length; i++) {
- newPassword[i] = (byte) newPasswordChars[i];
- }
- Arrays.fill(newPasswordChars, '\u0000');
- final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
- setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD, managedUserPassword,
- quality, managedUserId, false, /* isLockTiedToParent= */ true);
- // We store a private credential for the managed user that's unlocked by the primary
- // account holder's credential. As such, the user will never be prompted to enter this
- // password directly, so we always store a password.
- setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
- tieProfileLockToParent(managedUserId, newPassword);
- Arrays.fill(newPassword, (byte) 0);
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Fail to tie managed profile", e);
- // Nothing client can do to fix this issue, so we do not throw exception out
+ try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) {
+ setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId,
+ false, /* isLockTiedToParent= */ true);
+ tieProfileLockToParent(managedUserId, unifiedProfilePassword);
}
}
@@ -512,6 +515,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
+ int defaultValue) {
+ return Settings.Global.getInt(contentResolver, keyName, defaultValue);
+ }
}
public LockSettingsService(Context context) {
@@ -682,7 +689,7 @@ public class LockSettingsService extends ILockSettings.Stub {
hideEncryptionNotification(new UserHandle(userId));
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
- tieManagedProfileLockIfNecessary(userId, null);
+ tieManagedProfileLockIfNecessary(userId, LockscreenCredential.createNone());
}
// If the user doesn't have a credential, try and derive their secret for the
@@ -704,10 +711,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
final long handle = getSyntheticPasswordHandleLocked(userId);
- final byte[] noCredential = null;
AuthenticationResult result =
- mSpManager.unwrapPasswordBasedSyntheticPassword(
- getGateKeeperService(), handle, noCredential, userId, null);
+ mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
+ handle, LockscreenCredential.createNone(), userId, null);
if (result.authToken != null) {
Slog.i(TAG, "Retrieved auth token for user " + userId);
onAuthTokenKnownForUser(userId, result.authToken);
@@ -870,25 +876,6 @@ public class LockSettingsService extends ILockSettings.Stub {
final List<UserInfo> users = mUserManager.getUsers();
for (int i = 0; i < users.size(); i++) {
final UserInfo userInfo = users.get(i);
- if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
- // When managed profile has a unified lock, the password quality stored has 2
- // possibilities only.
- // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
- // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
- // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
- // unified lock.
- final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
- if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
- // Only possible when it's upgraded from nyc dp3
- Slog.i(TAG, "Migrated tied profile lock type");
- setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
- } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
- // It should not happen
- Slog.e(TAG, "Invalid tied profile lock type: " + quality);
- }
- }
try {
final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
java.security.KeyStore keyStore =
@@ -1031,21 +1018,22 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
- byte[] managedUserPassword) {
+ LockscreenCredential managedUserPassword) {
checkWritePermission(userId);
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
synchronized (mSeparateChallengeLock) {
- setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword);
+ setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword != null
+ ? managedUserPassword : LockscreenCredential.createNone());
}
notifySeparateProfileChallengeChanged(userId);
}
@GuardedBy("mSeparateChallengeLock")
private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
- boolean enabled, byte[] managedUserPassword) {
+ boolean enabled, LockscreenCredential managedUserPassword) {
final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
try {
@@ -1083,6 +1071,10 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void setLong(String key, long value, int userId) {
checkWritePermission(userId);
+ setLongUnchecked(key, value, userId);
+ }
+
+ private void setLongUnchecked(String key, long value, int userId) {
setStringUnchecked(key, userId, Long.toString(value));
}
@@ -1112,6 +1104,10 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public long getLong(String key, long defaultValue, int userId) {
checkReadPermission(key, userId);
+ return getLongUnchecked(key, defaultValue, userId);
+ }
+
+ private long getLongUnchecked(String key, long defaultValue, int userId) {
String value = getStringUnchecked(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
@@ -1122,7 +1118,7 @@ public class LockSettingsService extends ILockSettings.Stub {
return getStringUnchecked(key, defaultValue, userId);
}
- public String getStringUnchecked(String key, String defaultValue, int userId) {
+ private String getStringUnchecked(String key, String defaultValue, int userId) {
if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
long ident = Binder.clearCallingIdentity();
try {
@@ -1131,9 +1127,8 @@ public class LockSettingsService extends ILockSettings.Stub {
Binder.restoreCallingIdentity(ident);
}
}
-
if (userId == USER_FRP) {
- return getFrpStringUnchecked(key);
+ return null;
}
if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
@@ -1143,51 +1138,81 @@ public class LockSettingsService extends ILockSettings.Stub {
return mStorage.readKeyValue(key, defaultValue, userId);
}
- private String getFrpStringUnchecked(String key) {
- if (LockPatternUtils.PASSWORD_TYPE_KEY.equals(key)) {
- return String.valueOf(readFrpPasswordQuality());
- }
- return null;
+ private void setKeyguardStoredQuality(int quality, int userId) {
+ if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality);
+ setLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId);
}
- private int readFrpPasswordQuality() {
- return mStorage.readPersistentDataBlock().qualityForUi;
+ private int getKeyguardStoredQuality(int userId) {
+ return (int) getLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
}
@Override
- public boolean havePassword(int userId) {
+ public int getCredentialType(int userId) {
checkPasswordHavePermission(userId);
+ return getCredentialTypeInternal(userId);
+ }
+
+ // TODO: this is a hot path, can we optimize it?
+ /**
+ * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE},
+ * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and
+ * {@link #CREDENTIAL_TYPE_PASSWORD}
+ */
+ public int getCredentialTypeInternal(int userId) {
+ if (userId == USER_FRP) {
+ return getFrpCredentialType();
+ }
synchronized (mSpManager) {
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
final long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) == CREDENTIAL_TYPE_PASSWORD;
+ int rawType = mSpManager.getCredentialType(handle, userId);
+ if (rawType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
+ return rawType;
+ }
+ return pinOrPasswordQualityToCredentialType(getKeyguardStoredQuality(userId));
}
}
- // Do we need a permissions check here?
- return mStorage.hasPassword(userId);
+ // Intentional duplication of the getKeyguardStoredQuality() call above since this is a
+ // unlikely code path (device with pre-synthetic password credential). We want to skip
+ // calling getKeyguardStoredQuality whenever possible.
+ final int savedQuality = getKeyguardStoredQuality(userId);
+ if (savedQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
+ && mStorage.hasPattern(userId)) {
+ return CREDENTIAL_TYPE_PATTERN;
+ }
+ if (savedQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+ && mStorage.hasPassword(userId)) {
+ return pinOrPasswordQualityToCredentialType(savedQuality);
+ }
+ return CREDENTIAL_TYPE_NONE;
}
- @Override
- public boolean havePattern(int userId) {
- checkPasswordHavePermission(userId);
- synchronized (mSpManager) {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- final long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) == CREDENTIAL_TYPE_PATTERN;
- }
+ private int getFrpCredentialType() {
+ PersistentData data = mStorage.readPersistentDataBlock();
+ if (data.type != PersistentData.TYPE_SP && data.type != PersistentData.TYPE_SP_WEAVER) {
+ return CREDENTIAL_TYPE_NONE;
+ }
+ int credentialType = SyntheticPasswordManager.getFrpCredentialType(data.payload);
+ if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
+ return credentialType;
}
- // Do we need a permissions check here?
- return mStorage.hasPattern(userId);
+ return pinOrPasswordQualityToCredentialType(data.qualityForUi);
}
- private boolean isUserSecure(int userId) {
- synchronized (mSpManager) {
- if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- final long handle = getSyntheticPasswordHandleLocked(userId);
- return mSpManager.getCredentialType(handle, userId) != CREDENTIAL_TYPE_NONE;
- }
+ private static int pinOrPasswordQualityToCredentialType(int quality) {
+ if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
+ return CREDENTIAL_TYPE_PASSWORD;
+ }
+ if (LockPatternUtils.isQualityNumericPin(quality)) {
+ return CREDENTIAL_TYPE_PIN;
}
- return mStorage.hasCredential(userId);
+ throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
+ }
+
+ private boolean isUserSecure(int userId) {
+ return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
}
private void setKeystorePassword(byte[] password, int userHandle) {
@@ -1205,8 +1230,8 @@ public class LockSettingsService extends ILockSettings.Stub {
ks.unlock(userHandle, passwordString);
}
- @VisibleForTesting
- protected byte[] getDecryptedPasswordForTiedProfile(int userId)
+ @VisibleForTesting /** Note: this method is overridden in unit tests */
+ protected LockscreenCredential getDecryptedPasswordForTiedProfile(int userId)
throws KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
@@ -1230,7 +1255,10 @@ public class LockSettingsService extends ILockSettings.Stub {
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
decryptionResult = cipher.doFinal(encryptedPassword);
- return decryptionResult;
+ LockscreenCredential credential = LockscreenCredential.createManagedPassword(
+ decryptionResult);
+ Arrays.fill(decryptionResult, (byte) 0);
+ return credential;
}
private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated,
@@ -1238,7 +1266,6 @@ public class LockSettingsService extends ILockSettings.Stub {
@Nullable ArrayList<PendingResetLockout> resetLockouts) {
try {
doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
- CREDENTIAL_TYPE_PASSWORD,
challengeType, challenge, profileHandle, null /* progressCallback */,
resetLockouts);
} catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
@@ -1276,17 +1303,17 @@ public class LockSettingsService extends ILockSettings.Stub {
final IProgressListener listener = new IProgressListener.Stub() {
@Override
public void onStarted(int id, Bundle extras) throws RemoteException {
- Log.d(TAG, "unlockUser started");
+ Slog.d(TAG, "unlockUser started");
}
@Override
public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
- Log.d(TAG, "unlockUser progress " + progress);
+ Slog.d(TAG, "unlockUser progress " + progress);
}
@Override
public void onFinished(int id, Bundle extras) throws RemoteException {
- Log.d(TAG, "unlockUser finished");
+ Slog.d(TAG, "unlockUser finished");
latch.countDown();
}
};
@@ -1351,11 +1378,11 @@ public class LockSettingsService extends ILockSettings.Stub {
&& mUserManager.isUserRunning(userInfo.id);
}
- private Map<Integer, byte[]> getDecryptedPasswordsForAllTiedProfiles(int userId) {
+ private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return null;
}
- Map<Integer, byte[]> result = new ArrayMap<Integer, byte[]>();
+ Map<Integer, LockscreenCredential> result = new ArrayMap<>();
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
final int size = profiles.size();
for (int i = 0; i < size; i++) {
@@ -1393,7 +1420,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* terminates when the user is a managed profile.
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
- Map<Integer, byte[]> profilePasswordMap) {
+ Map<Integer, LockscreenCredential> profilePasswordMap) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return;
}
@@ -1408,20 +1435,23 @@ public class LockSettingsService extends ILockSettings.Stub {
continue;
}
if (isSecure) {
- tieManagedProfileLockIfNecessary(managedUserId, null);
+ tieManagedProfileLockIfNecessary(managedUserId,
+ LockscreenCredential.createNone());
} else {
// We use cached work profile password computed before clearing the parent's
// credential, otherwise they get lost
- if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
- setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE,
+ if (profilePasswordMap != null
+ && profilePasswordMap.containsKey(managedUserId)) {
+ setLockCredentialInternal(LockscreenCredential.createNone(),
profilePasswordMap.get(managedUserId),
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
+ managedUserId,
false, /* isLockTiedToParent= */ true);
} else {
Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
- // Supplying null here would lead to untrusted credential change
- setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE, null,
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
+ // Attempt an untrusted reset by supplying an empty credential.
+ setLockCredentialInternal(LockscreenCredential.createNone(),
+ LockscreenCredential.createNone(),
+ managedUserId,
true, /* isLockTiedToParent= */ true);
}
mStorage.removeChildProfileLock(managedUserId);
@@ -1445,8 +1475,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* Send credentials for user {@code userId} to {@link RecoverableKeyStoreManager} during an
* unlock operation.
*/
- private void sendCredentialsOnUnlockIfRequired(
- int credentialType, @NonNull byte[] credential, int userId) {
+ private void sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId) {
// Don't send credentials during the factory reset protection flow.
if (userId == USER_FRP) {
return;
@@ -1459,10 +1488,12 @@ public class LockSettingsService extends ILockSettings.Stub {
return;
}
+ // RecoverableKeyStoreManager expects null for empty credential.
+ final byte[] secret = credential.isNone() ? null : credential.getCredential();
// Send credentials for the user and any child profiles that share its lock screen.
for (int profileId : getProfilesWithSameLockScreen(userId)) {
mRecoverableKeyStoreManager.lockScreenSecretAvailable(
- credentialType, credential, profileId);
+ credential.getType(), secret, profileId);
}
}
@@ -1471,7 +1502,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* credentials are set/changed.
*/
private void sendCredentialsOnChangeIfRequired(
- int credentialType, byte[] credential, int userId, boolean isLockTiedToParent) {
+ LockscreenCredential credential, int userId, boolean isLockTiedToParent) {
// A profile whose lock screen is being tied to its parent's will either have a randomly
// generated credential (creation) or null (removal). We rely on the parent to send its
// credentials for the profile in both cases as it stores the unified lock credential.
@@ -1479,10 +1510,12 @@ public class LockSettingsService extends ILockSettings.Stub {
return;
}
+ // RecoverableKeyStoreManager expects null for empty credential.
+ final byte[] secret = credential.isNone() ? null : credential.getCredential();
// Send credentials for the user and any child profiles that share its lock screen.
for (int profileId : getProfilesWithSameLockScreen(userId)) {
mRecoverableKeyStoreManager.lockScreenSecretChanged(
- credentialType, credential, profileId);
+ credential.getType(), secret, profileId);
}
}
@@ -1505,9 +1538,8 @@ public class LockSettingsService extends ILockSettings.Stub {
// This method should be called by LockPatternUtil only, all internal methods in this class
// should call setLockCredentialInternal.
@Override
- public boolean setLockCredential(byte[] credential, int type,
- byte[] savedCredential, int requestedQuality, int userId,
- boolean allowUntrustedChange) {
+ public boolean setLockCredential(LockscreenCredential credential,
+ LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -1515,11 +1547,11 @@ public class LockSettingsService extends ILockSettings.Stub {
}
checkWritePermission(userId);
synchronized (mSeparateChallengeLock) {
- if (!setLockCredentialInternal(credential, type, savedCredential, requestedQuality,
+ if (!setLockCredentialInternal(credential, savedCredential,
userId, allowUntrustedChange, /* isLockTiedToParent= */ false)) {
return false;
}
- setSeparateProfileChallengeEnabledLocked(userId, true, null);
+ setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
notifyPasswordChanged(userId);
}
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
@@ -1531,51 +1563,44 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
+ * @param savedCredential if the user is a managed profile with unified challenge and
+ * savedCredential is empty, LSS will try to re-derive the profile password internally.
+ * TODO (b/80170828): Fix this so profile password is always passed in.
* @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
* credentials are being tied to its parent's credentials.
*/
- private boolean setLockCredentialInternal(byte[] credential, @CredentialType int credentialType,
- byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange,
- boolean isLockTiedToParent) {
- // Normalize savedCredential and credential such that empty string is always represented
- // as null.
- if (savedCredential == null || savedCredential.length == 0) {
- savedCredential = null;
- }
- if (credential == null || credential.length == 0) {
- credential = null;
- }
+ private boolean setLockCredentialInternal(LockscreenCredential credential,
+ LockscreenCredential savedCredential, int userId,
+ boolean allowUntrustedChange, boolean isLockTiedToParent) {
+ Preconditions.checkNotNull(credential);
+ Preconditions.checkNotNull(savedCredential);
synchronized (mSpManager) {
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
- return spBasedSetLockCredentialInternalLocked(credential, credentialType,
- savedCredential, requestedQuality, userId, allowUntrustedChange,
- isLockTiedToParent);
+ return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
+ allowUntrustedChange, isLockTiedToParent);
}
}
- if (credentialType == CREDENTIAL_TYPE_NONE) {
- if (credential != null) {
- Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
- }
+ if (credential.isNone()) {
clearUserKeyProtection(userId);
gateKeeperClearSecureUserId(userId);
mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
+ // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path,
+ // since it forms part of the state that determines the credential type
+ // @see getCredentialTypeInternal
+ setKeyguardStoredQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
setKeystorePassword(null, userId);
fixateNewestUserKeyAuth(userId);
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
- setUserPasswordMetrics(CREDENTIAL_TYPE_NONE, null, userId);
- sendCredentialsOnChangeIfRequired(
- credentialType, credential, userId, isLockTiedToParent);
+ setUserPasswordMetrics(LockscreenCredential.createNone(), userId);
+ sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
return true;
}
- if (credential == null) {
- throw new IllegalArgumentException("Null credential with mismatched credential type");
- }
CredentialHash currentHandle = mStorage.readCredentialHash(userId);
if (isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
- if (savedCredential == null) {
+ if (savedCredential.isNone()) {
try {
savedCredential = getDecryptedPasswordForTiedProfile(userId);
} catch (FileNotFoundException e) {
@@ -1589,47 +1614,50 @@ public class LockSettingsService extends ILockSettings.Stub {
}
} else {
if (currentHandle.hash == null) {
- if (savedCredential != null) {
+ if (!savedCredential.isNone()) {
Slog.w(TAG, "Saved credential provided, but none stored");
}
- savedCredential = null;
+ savedCredential.close();
+ savedCredential = LockscreenCredential.createNone();
}
}
synchronized (mSpManager) {
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
- initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
- currentHandle.type, requestedQuality, userId);
- return spBasedSetLockCredentialInternalLocked(credential, credentialType,
- savedCredential, requestedQuality, userId, allowUntrustedChange,
- isLockTiedToParent);
+ initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
+ return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
+ allowUntrustedChange, isLockTiedToParent);
}
}
if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
- byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
- userId);
+ byte[] enrolledHandle = enrollCredential(currentHandle.hash,
+ savedCredential.getCredential(), credential.getCredential(), userId);
if (enrolledHandle == null) {
Slog.w(TAG, String.format("Failed to enroll %s: incorrect credential",
- credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
+ credential.isPattern() ? "pattern" : "password"));
return false;
}
- CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
+ CredentialHash willStore = CredentialHash.create(enrolledHandle, credential.getType());
mStorage.writeCredentialHash(willStore, userId);
+ // Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path,
+ // since it forms part of the state that determines the credential type
+ // @see getCredentialTypeInternal
+ setKeyguardStoredQuality(
+ LockPatternUtils.credentialTypeToPasswordQuality(credential.getType()), userId);
// push new secret and auth token to vold
GateKeeperResponse gkResponse;
try {
gkResponse = getGateKeeperService().verifyChallenge(userId, 0, willStore.hash,
- credential);
+ credential.getCredential());
} catch (RemoteException e) {
throw new IllegalStateException("Failed to verify current credential", e);
}
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
fixateNewestUserKeyAuth(userId);
// Refresh the auth token
- doVerifyCredential(credential, credentialType, CHALLENGE_FROM_CALLER, 0, userId,
+ doVerifyCredential(credential, CHALLENGE_FROM_CALLER, 0, userId,
null /* progressCallback */);
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
- sendCredentialsOnChangeIfRequired(
- credentialType, credential, userId, isLockTiedToParent);
+ sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
return true;
}
@@ -1637,8 +1665,8 @@ public class LockSettingsService extends ILockSettings.Stub {
return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
}
- @VisibleForTesting
- protected void tieProfileLockToParent(int userId, byte[] password) {
+ @VisibleForTesting /** Note: this method is overridden in unit tests */
+ protected void tieProfileLockToParent(int userId, LockscreenCredential password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
byte[] encryptionResult;
byte[] iv;
@@ -1673,7 +1701,7 @@ public class LockSettingsService extends ILockSettings.Stub {
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
+ KeyProperties.ENCRYPTION_PADDING_NONE);
cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
- encryptionResult = cipher.doFinal(password);
+ encryptionResult = cipher.doFinal(password.getCredential());
iv = cipher.getIV();
} finally {
// The original key can now be discarded.
@@ -1728,7 +1756,8 @@ public class LockSettingsService extends ILockSettings.Stub {
addUserKeyAuth(userId, null, key);
}
- private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) {
+ private void setUserKeyProtection(int userId, LockscreenCredential credential,
+ VerifyCredentialResponse vcr) {
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
if (vcr == null) {
throw new IllegalArgumentException("Null response verifying a credential we just set");
@@ -1749,7 +1778,7 @@ public class LockSettingsService extends ILockSettings.Stub {
addUserKeyAuth(userId, null, null);
}
- private static byte[] secretFromCredential(byte[] credential) {
+ private static byte[] secretFromCredential(LockscreenCredential credential) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
// Personalize the hash
@@ -1757,7 +1786,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// Pad it to the block size of the hash function
personalization = Arrays.copyOf(personalization, 128);
digest.update(personalization);
- digest.update(credential);
+ digest.update(credential.getCredential());
return digest.digest();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("NoSuchAlgorithmException for SHA-512");
@@ -1768,7 +1797,7 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
return mStorageManager.isUserKeyUnlocked(userId);
} catch (RemoteException e) {
- Log.e(TAG, "failed to check user key locked state", e);
+ Slog.e(TAG, "failed to check user key locked state", e);
return false;
}
}
@@ -1815,7 +1844,7 @@ public class LockSettingsService extends ILockSettings.Stub {
checkWritePermission(userId);
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
int managedUserId = -1;
- byte[] managedUserDecryptedPassword = null;
+ LockscreenCredential managedUserDecryptedPassword = null;
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock managed profile with unified lock
@@ -1852,30 +1881,30 @@ public class LockSettingsService extends ILockSettings.Stub {
tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
}
}
- if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) {
- Arrays.fill(managedUserDecryptedPassword, (byte) 0);
+ if (managedUserDecryptedPassword != null) {
+ managedUserDecryptedPassword.zeroize();
}
}
@Override
- public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
+ public VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,
ICheckCredentialProgressCallback progressCallback) {
checkPasswordReadPermission(userId);
- return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback);
+ return doVerifyCredential(credential, CHALLENGE_NONE, 0, userId, progressCallback);
}
@Override
- public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
- int userId) {
+ public VerifyCredentialResponse verifyCredential(LockscreenCredential credential,
+ long challenge, int userId) {
checkPasswordReadPermission(userId);
- return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId,
+ return doVerifyCredential(credential, CHALLENGE_FROM_CALLER, challenge, userId,
null /* progressCallback */);
}
- private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
+ private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential,
@ChallengeType int challengeType, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) {
- return doVerifyCredential(credential, credentialType, challengeType, challenge, userId,
+ return doVerifyCredential(credential, challengeType, challenge, userId,
progressCallback, null /* resetLockouts */);
}
@@ -1883,25 +1912,25 @@ public class LockSettingsService extends ILockSettings.Stub {
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
* format.
*/
- private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
+ private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential,
@ChallengeType int challengeType, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback,
@Nullable ArrayList<PendingResetLockout> resetLockouts) {
- if (credential == null || credential.length == 0) {
+ if (credential == null || credential.isNone()) {
throw new IllegalArgumentException("Credential can't be null or empty");
}
- if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
+ if (userId == USER_FRP && mInjector.settingsGlobalGetInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
return VerifyCredentialResponse.ERROR;
}
VerifyCredentialResponse response = null;
- response = spBasedDoVerifyCredential(credential, credentialType, challengeType, challenge,
+ response = spBasedDoVerifyCredential(credential, challengeType, challenge,
userId, progressCallback, resetLockouts);
// The user employs synthetic password based credential.
if (response != null) {
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
- sendCredentialsOnUnlockIfRequired(credentialType, credential, userId);
+ sendCredentialsOnUnlockIfRequired(credential, userId);
}
return response;
}
@@ -1912,9 +1941,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
final CredentialHash storedHash = mStorage.readCredentialHash(userId);
- if (storedHash.type != credentialType) {
+ if (!credential.checkAgainstStoredType(storedHash.type)) {
Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
- + " stored: " + storedHash.type + " passed in: " + credentialType);
+ + " stored: " + storedHash.type + " passed in: " + credential.getType());
return VerifyCredentialResponse.ERROR;
}
@@ -1929,7 +1958,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type,
+ public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential,
long challenge, int userId) {
checkPasswordReadPermission(userId);
if (!isManagedProfileWithUnifiedLock(userId)) {
@@ -1939,7 +1968,6 @@ public class LockSettingsService extends ILockSettings.Stub {
// Unlock parent by using parent's challenge
final VerifyCredentialResponse parentResponse = doVerifyCredential(
credential,
- type,
CHALLENGE_FROM_CALLER,
challenge,
parentProfileId,
@@ -1952,7 +1980,6 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
// Unlock work profile, and work profile with unified lock must use password only
return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
- CREDENTIAL_TYPE_PASSWORD,
CHALLENGE_FROM_CALLER,
challenge,
userId, null /* progressCallback */);
@@ -1971,15 +1998,14 @@ public class LockSettingsService extends ILockSettings.Stub {
* hash to GK.
*/
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
- byte[] credential, @ChallengeType int challengeType, long challenge,
+ LockscreenCredential credential, @ChallengeType int challengeType, long challenge,
ICheckCredentialProgressCallback progressCallback) {
- if ((storedHash == null || storedHash.hash.length == 0)
- && (credential == null || credential.length == 0)) {
+ if ((storedHash == null || storedHash.hash.length == 0) && credential.isNone()) {
// don't need to pass empty credentials to GateKeeper
return VerifyCredentialResponse.OK;
}
- if (storedHash == null || credential == null || credential.length == 0) {
+ if (storedHash == null || storedHash.hash.length == 0 || credential.isNone()) {
return VerifyCredentialResponse.ERROR;
}
@@ -1989,8 +2015,8 @@ public class LockSettingsService extends ILockSettings.Stub {
GateKeeperResponse gateKeeperResponse;
try {
- gateKeeperResponse = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, credential);
+ gateKeeperResponse = getGateKeeperService().verifyChallenge(
+ userId, challenge, storedHash.hash, credential.getCredential());
} catch (RemoteException e) {
Slog.e(TAG, "gatekeeper verify failed", e);
gateKeeperResponse = GateKeeperResponse.ERROR;
@@ -2006,11 +2032,11 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
progressCallback.onCredentialVerified();
} catch (RemoteException e) {
- Log.w(TAG, "progressCallback throws exception", e);
+ Slog.w(TAG, "progressCallback throws exception", e);
}
}
- setUserPasswordMetrics(storedHash.type, credential, userId);
- unlockKeystore(credential, userId);
+ setUserPasswordMetrics(credential, userId);
+ unlockKeystore(credential.getCredential(), userId);
Slog.i(TAG, "Unlocking user " + userId + " with token length "
+ response.getPayload().length);
@@ -2019,27 +2045,22 @@ public class LockSettingsService extends ILockSettings.Stub {
if (isManagedProfileWithSeparatedLock(userId)) {
setDeviceUnlockedForUser(userId);
}
- int reEnrollQuality = storedHash.type == CREDENTIAL_TYPE_PATTERN
- ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
- : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
- /* TODO(roosa): keep the same password quality */;
if (shouldReEnroll) {
- setLockCredentialInternal(credential, storedHash.type, credential,
- reEnrollQuality, userId, false, /* isLockTiedToParent= */ false);
+ setLockCredentialInternal(credential, credential,
+ userId, false, /* isLockTiedToParent= */ false);
} else {
// Now that we've cleared of all required GK migration, let's do the final
// migration to synthetic password.
synchronized (mSpManager) {
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
AuthenticationToken auth = initializeSyntheticPasswordLocked(
- storedHash.hash, credential, storedHash.type, reEnrollQuality,
- userId);
+ storedHash.hash, credential, userId);
activateEscrowTokens(auth, userId);
}
}
}
// Use credentials to create recoverable keystore snapshot.
- sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId);
+ sendCredentialsOnUnlockIfRequired(credential, userId);
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
if (response.getTimeout() > 0) {
@@ -2055,12 +2076,9 @@ public class LockSettingsService extends ILockSettings.Stub {
* when the user is authenticating or when a new password is being set. In comparison,
* {@link #notifyPasswordChanged} only needs to be called when the user changes the password.
*/
- private void setUserPasswordMetrics(@CredentialType int credentialType, byte[] password,
- @UserIdInt int userHandle) {
+ private void setUserPasswordMetrics(LockscreenCredential password, @UserIdInt int userHandle) {
synchronized (this) {
- mUserPasswordMetrics.put(userHandle,
- PasswordMetrics.computeForCredential(
- LockscreenCredential.createRaw(credentialType, password)));
+ mUserPasswordMetrics.put(userHandle, PasswordMetrics.computeForCredential(password));
}
}
@@ -2089,6 +2107,14 @@ public class LockSettingsService extends ILockSettings.Stub {
});
}
+ private LockscreenCredential createPattern(String patternString) {
+ final byte[] patternBytes = patternString.getBytes();
+ LockscreenCredential pattern = LockscreenCredential.createPattern(
+ LockPatternUtils.byteArrayToPattern(patternBytes));
+ Arrays.fill(patternBytes, (byte) 0);
+ return pattern;
+ }
+
@Override
public boolean checkVoldPassword(int userId) {
if (!mFirstCallToVold) {
@@ -2119,30 +2145,34 @@ public class LockSettingsService extends ILockSettings.Stub {
} finally {
Binder.restoreCallingIdentity(identity);
}
- if (password == null) {
+ if (TextUtils.isEmpty(password)) {
return false;
}
try {
- if (mLockPatternUtils.isLockPatternEnabled(userId)) {
- if (checkCredential(password.getBytes(), CREDENTIAL_TYPE_PATTERN,
- userId, null /* progressCallback */)
- .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
- return true;
- }
- }
- } catch (Exception e) {
- }
-
- try {
- if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
- if (checkCredential(password.getBytes(), CREDENTIAL_TYPE_PASSWORD,
- userId, null /* progressCallback */)
+ final LockscreenCredential credential;
+ switch (getCredentialTypeInternal(userId)) {
+ case CREDENTIAL_TYPE_PATTERN:
+ credential = createPattern(password);
+ break;
+ case CREDENTIAL_TYPE_PIN:
+ credential = LockscreenCredential.createPin(password);
+ break;
+ case CREDENTIAL_TYPE_PASSWORD:
+ credential = LockscreenCredential.createPassword(password);
+ break;
+ default:
+ credential = null;
+ Slog.e(TAG, "Unknown credential type");
+ }
+
+ if (credential != null
+ && checkCredential(credential, userId, null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
- return true;
- }
+ return true;
}
} catch (Exception e) {
+ Slog.e(TAG, "checkVoldPassword failed: ", e);
}
return false;
@@ -2524,7 +2554,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@GuardedBy("mSpManager")
@VisibleForTesting
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
- byte[] credential, int credentialType, int requestedQuality, int userId) {
+ LockscreenCredential credential, int userId) {
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
getGateKeeperService(), credentialHash, credential, userId);
@@ -2534,8 +2564,8 @@ public class LockSettingsService extends ILockSettings.Stub {
return null;
}
long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
- credential, credentialType, auth, requestedQuality, userId);
- if (credential != null) {
+ credential, auth, userId);
+ if (!credential.isNone()) {
if (credentialHash == null) {
// Since when initializing SP, we didn't provide an existing password handle
// for it to migrate SID, we need to create a new SID for the user.
@@ -2567,6 +2597,13 @@ public class LockSettingsService extends ILockSettings.Stub {
}
+ @VisibleForTesting
+ boolean isSyntheticPasswordBasedCredential(int userId) {
+ synchronized (mSpManager) {
+ return isSyntheticPasswordBasedCredentialLocked(userId);
+ }
+ }
+
private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
if (userId == USER_FRP) {
final int type = mStorage.readPersistentDataBlock().type;
@@ -2592,8 +2629,8 @@ public class LockSettingsService extends ILockSettings.Stub {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
- private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
- @CredentialType int credentialType, @ChallengeType int challengeType, long challenge,
+ private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential,
+ @ChallengeType int challengeType, long challenge,
int userId, ICheckCredentialProgressCallback progressCallback,
@Nullable ArrayList<PendingResetLockout> resetLockouts) {
@@ -2601,9 +2638,6 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " challengeType=" + challengeType
+ " hasEnrolledBiometrics=" + hasEnrolledBiometrics);
- if (credentialType == CREDENTIAL_TYPE_NONE) {
- userCredential = null;
- }
final PackageManager pm = mContext.getPackageManager();
// TODO: When lockout is handled under the HAL for all biometrics (fingerprint),
@@ -2625,17 +2659,13 @@ public class LockSettingsService extends ILockSettings.Stub {
}
if (userId == USER_FRP) {
return mSpManager.verifyFrpCredential(getGateKeeperService(),
- userCredential, credentialType, progressCallback);
+ userCredential, progressCallback);
}
long handle = getSyntheticPasswordHandleLocked(userId);
authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
getGateKeeperService(), handle, userCredential, userId, progressCallback);
- if (authResult.credentialType != credentialType) {
- Slog.e(TAG, "Credential type mismatch.");
- return VerifyCredentialResponse.ERROR;
- }
response = authResult.gkResponse;
// credential has matched
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -2653,7 +2683,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
- setUserPasswordMetrics(credentialType, userCredential, userId);
+ setUserPasswordMetrics(userCredential, userId);
unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
// Do resetLockout / revokeChallenge when all profiles are unlocked
@@ -2700,14 +2730,13 @@ public class LockSettingsService extends ILockSettings.Stub {
* added back when new password is set in future.
*/
@GuardedBy("mSpManager")
- private long setLockCredentialWithAuthTokenLocked(byte[] credential,
- @CredentialType int credentialType, AuthenticationToken auth, int requestedQuality,
- int userId) {
+ private long setLockCredentialWithAuthTokenLocked(LockscreenCredential credential,
+ AuthenticationToken auth, int userId) {
if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
- credential, credentialType, auth, requestedQuality, userId);
- final Map<Integer, byte[]> profilePasswords;
- if (credential != null) {
+ credential, auth, userId);
+ final Map<Integer, LockscreenCredential> profilePasswords;
+ if (!credential.isNone()) {
// not needed by synchronizeUnifiedWorkChallengeForProfiles()
profilePasswords = null;
@@ -2748,11 +2777,11 @@ public class LockSettingsService extends ILockSettings.Stub {
setSyntheticPasswordHandleLocked(newHandle, userId);
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
- setUserPasswordMetrics(credentialType, credential, userId);
+ setUserPasswordMetrics(credential, userId);
if (profilePasswords != null) {
- for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
- Arrays.fill(entry.getValue(), (byte) 0);
+ for (Map.Entry<Integer, LockscreenCredential> entry : profilePasswords.entrySet()) {
+ entry.getValue().zeroize();
}
}
@@ -2838,12 +2867,17 @@ public class LockSettingsService extends ILockSettings.Stub {
};
}
+ /**
+ * @param savedCredential if the user is a managed profile with unified challenge and
+ * savedCredential is empty, LSS will try to re-derive the profile password internally.
+ * TODO (b/80170828): Fix this so profile password is always passed in.
+ */
@GuardedBy("mSpManager")
- private boolean spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
- byte[] savedCredential, int requestedQuality, int userId,
+ private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential,
+ LockscreenCredential savedCredential, int userId,
boolean allowUntrustedChange, boolean isLockTiedToParent) {
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
- if (isManagedProfileWithUnifiedLock(userId)) {
+ if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
try {
savedCredential = getDecryptedPasswordForTiedProfile(userId);
@@ -2863,9 +2897,8 @@ public class LockSettingsService extends ILockSettings.Stub {
AuthenticationToken auth = authResult.authToken;
// If existing credential is provided, the existing credential must match.
- if (savedCredential != null && auth == null) {
- Slog.w(TAG, String.format("Failed to enroll %s: incorrect credential",
- credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
+ if (!savedCredential.isNone() && auth == null) {
+ Slog.w(TAG, "Failed to enroll: incorrect credential");
return false;
}
boolean untrustedReset = false;
@@ -2898,8 +2931,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// setLockCredentialWithAuthTokenLocked next
mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
}
- setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, requestedQuality,
- userId);
+ setLockCredentialWithAuthTokenLocked(credential, auth, userId);
mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
} else {
throw new IllegalStateException(
@@ -2908,7 +2940,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// requestedQuality, userId) instead if we still allow untrusted reset that changes
// synthetic password. That would invalidate existing escrow tokens though.
}
- sendCredentialsOnChangeIfRequired(credentialType, credential, userId, isLockTiedToParent);
+ sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
return true;
}
@@ -2919,11 +2951,8 @@ public class LockSettingsService extends ILockSettings.Stub {
* If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
- public byte[] getHashFactor(byte[] currentCredential, int userId) {
+ public byte[] getHashFactor(LockscreenCredential currentCredential, int userId) {
checkPasswordReadPermission(userId);
- if (currentCredential == null || currentCredential.length == 0) {
- currentCredential = null;
- }
if (isManagedProfileWithUnifiedLock(userId)) {
try {
currentCredential = getDecryptedPasswordForTiedProfile(userId);
@@ -2957,13 +2986,12 @@ public class LockSettingsService extends ILockSettings.Stub {
AuthenticationToken auth = null;
if (!isUserSecure(userId)) {
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
- auth = initializeSyntheticPasswordLocked(null, null,
- CREDENTIAL_TYPE_NONE,
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
+ auth = initializeSyntheticPasswordLocked(
+ /* credentialHash */ null, LockscreenCredential.createNone(), userId);
} else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
long pwdHandle = getSyntheticPasswordHandleLocked(userId);
auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
- pwdHandle, null, userId, null).authToken;
+ pwdHandle, LockscreenCredential.createNone(), userId, null).authToken;
}
}
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
@@ -3023,21 +3051,21 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle,
- byte[] token, int requestedQuality, int userId) {
+ private boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
+ byte[] token, int userId) {
boolean result;
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
throw new SecurityException("Escrow token is disabled on the current user");
}
- result = setLockCredentialWithTokenInternalLocked(credential, type, tokenHandle, token,
- requestedQuality, userId);
+ result = setLockCredentialWithTokenInternalLocked(
+ credential, tokenHandle, token, userId);
}
if (result) {
synchronized (mSeparateChallengeLock) {
- setSeparateProfileChallengeEnabledLocked(userId, true, null);
+ setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
}
- if (credential == null) {
+ if (credential.isNone()) {
// If clearing credential, unlock the user manually in order to progress user start
// Call unlockUser() on a handler thread so no lock is held (either by LSS or by
// the caller like DPMS), otherwise it can lead to deadlock.
@@ -3050,8 +3078,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@GuardedBy("mSpManager")
- private boolean setLockCredentialWithTokenInternalLocked(byte[] credential, int type,
- long tokenHandle, byte[] token, int requestedQuality, int userId) {
+ private boolean setLockCredentialWithTokenInternalLocked(LockscreenCredential credential,
+ long tokenHandle, byte[] token, int userId) {
final AuthenticationResult result;
result = mSpManager.unwrapTokenBasedSyntheticPassword(
getGateKeeperService(), tokenHandle, token, userId);
@@ -3066,11 +3094,8 @@ public class LockSettingsService extends ILockSettings.Stub {
+ "verification.");
return false;
}
- // TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
- setLong(LockPatternUtils.PASSWORD_TYPE_KEY, requestedQuality, userId);
long oldHandle = getSyntheticPasswordHandleLocked(userId);
- setLockCredentialWithAuthTokenLocked(credential, type, result.authToken,
- requestedQuality, userId);
+ setLockCredentialWithAuthTokenLocked(credential, result.authToken, userId);
mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
onAuthTokenKnownForUser(userId, result.authToken);
@@ -3132,11 +3157,10 @@ public class LockSettingsService extends ILockSettings.Stub {
}
// It's OK to dump the password type since anyone with physical access can just
// observe it from the keyguard directly.
- pw.println("PasswordType: " + getLong(LockPatternUtils.PASSWORD_TYPE_KEY, 0, userId));
- pw.println("hasPassword: " + havePassword(userId));
- pw.println("hasPattern: " + havePattern(userId)); // print raw credential type instead?
+ pw.println("Quality: " + getKeyguardStoredQuality(userId));
+ pw.println("CredentialType: " + getCredentialTypeInternal(userId));
pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId));
- pw.println(String.format("metrics: %s",
+ pw.println(String.format("Metrics: %s",
getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
pw.decreaseIndent();
}
@@ -3298,14 +3322,14 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public boolean setLockCredentialWithToken(byte[] credential, int type,
- long tokenHandle, byte[] token, int requestedQuality, int userId) {
+ public boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
+ byte[] token, int userId) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
}
- return LockSettingsService.this.setLockCredentialWithToken(credential, type,
- tokenHandle, token, requestedQuality, userId);
+ return LockSettingsService.this.setLockCredentialWithToken(
+ credential, tokenHandle, token, userId);
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 0a8e5bd7ad4b..71c7b23a3a0d 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -243,9 +243,7 @@ class LockSettingsShellCommand extends ShellCommand {
}
private boolean checkCredential() {
- final boolean havePassword = mLockPatternUtils.isLockPasswordEnabled(mCurrentUserId);
- final boolean havePattern = mLockPatternUtils.isLockPatternEnabled(mCurrentUserId);
- if (havePassword || havePattern) {
+ if (mLockPatternUtils.isSecure(mCurrentUserId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(mCurrentUserId)) {
getOutPrintWriter().println("Profile uses unified challenge");
return false;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index f4cad634ac1a..3dab3ce7116c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -30,7 +30,6 @@ import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -214,7 +213,7 @@ class LockSettingsStorage {
private CredentialHash readPasswordHashIfExists(int userId) {
byte[] stored = readFile(getLockPasswordFilename(userId));
if (!ArrayUtils.isEmpty(stored)) {
- return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
+ return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN);
}
return null;
}
@@ -270,10 +269,6 @@ class LockSettingsStorage {
return hasFile(getLockPatternFilename(userId));
}
- public boolean hasCredential(int userId) {
- return hasPassword(userId) || hasPattern(userId);
- }
-
private boolean hasFile(String name) {
byte[] contents = readFile(name);
return contents != null && contents.length > 0;
@@ -360,11 +355,15 @@ class LockSettingsStorage {
public void writeCredentialHash(CredentialHash hash, int userId) {
byte[] patternHash = null;
byte[] passwordHash = null;
-
- if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN
+ || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
+ || hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN) {
passwordHash = hash.hash;
} else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
patternHash = hash.hash;
+ } else {
+ Preconditions.checkArgument(hash.type == LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ "Unknown credential type");
}
writeFile(getLockPasswordFilename(userId), passwordHash);
writeFile(getLockPatternFilename(userId), patternHash);
@@ -523,8 +522,8 @@ class LockSettingsStorage {
mCache.clear();
}
- @Nullable
- public PersistentDataBlockManagerInternal getPersistentDataBlock() {
+ @Nullable @VisibleForTesting
+ PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
if (mPersistentDataBlockManagerInternal == null) {
mPersistentDataBlockManagerInternal =
LocalServices.getService(PersistentDataBlockManagerInternal.class);
@@ -534,7 +533,7 @@ class LockSettingsStorage {
public void writePersistentDataBlock(int persistentType, int userId, int qualityForUi,
byte[] payload) {
- PersistentDataBlockManagerInternal persistentDataBlock = getPersistentDataBlock();
+ PersistentDataBlockManagerInternal persistentDataBlock = getPersistentDataBlockManager();
if (persistentDataBlock == null) {
return;
}
@@ -543,7 +542,7 @@ class LockSettingsStorage {
}
public PersistentData readPersistentDataBlock() {
- PersistentDataBlockManagerInternal persistentDataBlock = getPersistentDataBlock();
+ PersistentDataBlockManagerInternal persistentDataBlock = getPersistentDataBlockManager();
if (persistentDataBlock == null) {
return PersistentData.NONE;
}
@@ -699,7 +698,7 @@ class LockSettingsStorage {
}
if (upgradeVersion != DATABASE_VERSION) {
- Log.w(TAG, "Failed to upgrade database!");
+ Slog.w(TAG, "Failed to upgrade database!");
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 955a9aa8d0de..53d922b6da9f 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -20,7 +20,6 @@ import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChang
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.hardware.weaver.V1_0.IWeaver;
@@ -35,13 +34,13 @@ import android.security.Scrypt;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
@@ -138,7 +137,6 @@ public class SyntheticPasswordManager {
static class AuthenticationResult {
public AuthenticationToken authToken;
public VerifyCredentialResponse gkResponse;
- public int credentialType;
}
static class AuthenticationToken {
@@ -220,7 +218,7 @@ public class SyntheticPasswordManager {
byte scryptN;
byte scryptR;
byte scryptP;
- public int passwordType;
+ public int credentialType;
byte[] salt;
// For GateKeeper-based credential, this is the password handle returned by GK,
// for weaver-based credential, this is empty.
@@ -231,7 +229,7 @@ public class SyntheticPasswordManager {
result.scryptN = PASSWORD_SCRYPT_N;
result.scryptR = PASSWORD_SCRYPT_R;
result.scryptP = PASSWORD_SCRYPT_P;
- result.passwordType = passwordType;
+ result.credentialType = passwordType;
result.salt = secureRandom(PASSWORD_SALT_LENGTH);
return result;
}
@@ -241,7 +239,7 @@ public class SyntheticPasswordManager {
ByteBuffer buffer = ByteBuffer.allocate(data.length);
buffer.put(data, 0, data.length);
buffer.flip();
- result.passwordType = buffer.getInt();
+ result.credentialType = buffer.getInt();
result.scryptN = buffer.get();
result.scryptR = buffer.get();
result.scryptP = buffer.get();
@@ -263,7 +261,7 @@ public class SyntheticPasswordManager {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + 3 * Byte.BYTES
+ Integer.BYTES + salt.length + Integer.BYTES +
(passwordHandle != null ? passwordHandle.length : 0));
- buffer.putInt(passwordType);
+ buffer.putInt(credentialType);
buffer.put(scryptN);
buffer.put(scryptR);
buffer.put(scryptP);
@@ -366,11 +364,11 @@ public class SyntheticPasswordManager {
try {
int writeStatus = mWeaver.write(slot, toByteArrayList(key), toByteArrayList(value));
if (writeStatus != WeaverStatus.OK) {
- Log.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
+ Slog.e(TAG, "weaver write failed, slot: " + slot + " status: " + writeStatus);
return null;
}
} catch (RemoteException e) {
- Log.e(TAG, "weaver write failed", e);
+ Slog.e(TAG, "weaver write failed", e);
return null;
}
return value;
@@ -401,31 +399,31 @@ public class SyntheticPasswordManager {
break;
case WeaverReadStatus.THROTTLE:
response[0] = new VerifyCredentialResponse(readResponse.timeout);
- Log.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
+ Slog.e(TAG, "weaver read failed (THROTTLE), slot: " + slot);
break;
case WeaverReadStatus.INCORRECT_KEY:
if (readResponse.timeout == 0) {
response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
+ Slog.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot);
} else {
response[0] = new VerifyCredentialResponse(readResponse.timeout);
- Log.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
+ Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: "
+ slot);
}
break;
case WeaverReadStatus.FAILED:
response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read failed (FAILED), slot: " + slot);
+ Slog.e(TAG, "weaver read failed (FAILED), slot: " + slot);
break;
default:
response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
+ Slog.e(TAG, "weaver read unknown status " + status + ", slot: " + slot);
break;
}
});
} catch (RemoteException e) {
response[0] = VerifyCredentialResponse.ERROR;
- Log.e(TAG, "weaver read failed, slot: " + slot, e);
+ Slog.e(TAG, "weaver read failed, slot: " + slot, e);
}
return response[0];
}
@@ -437,13 +435,20 @@ public class SyntheticPasswordManager {
}
}
- public int getCredentialType(long handle, int userId) {
+ int getCredentialType(long handle, int userId) {
byte[] passwordData = loadState(PASSWORD_DATA_NAME, handle, userId);
if (passwordData == null) {
- Log.w(TAG, "getCredentialType: encountered empty password data for user " + userId);
+ Slog.w(TAG, "getCredentialType: encountered empty password data for user " + userId);
+ return LockPatternUtils.CREDENTIAL_TYPE_NONE;
+ }
+ return PasswordData.fromBytes(passwordData).credentialType;
+ }
+
+ static int getFrpCredentialType(byte[] payload) {
+ if (payload == null) {
return LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
- return PasswordData.fromBytes(passwordData).passwordType;
+ return PasswordData.fromBytes(payload).credentialType;
}
/**
@@ -469,17 +474,18 @@ public class SyntheticPasswordManager {
*
*/
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
- byte[] hash, byte[] credential, int userId) {
+ byte[] hash, LockscreenCredential credential, int userId) {
AuthenticationToken result = AuthenticationToken.create();
GateKeeperResponse response;
if (hash != null) {
try {
- response = gatekeeper.enroll(userId, hash, credential, result.deriveGkPassword());
+ response = gatekeeper.enroll(userId, hash, credential.getCredential(),
+ result.deriveGkPassword());
} catch (RemoteException e) {
throw new IllegalStateException("Failed to enroll credential duing SP init", e);
}
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
- Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
+ Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
clearSidForUser(userId);
} else {
saveSyntheticPasswordHandle(response.getPayload(), userId);
@@ -504,7 +510,7 @@ public class SyntheticPasswordManager {
throw new IllegalStateException("Failed to create new SID for user", e);
}
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
- Log.e(TAG, "Fail to create new SID for user " + userId);
+ Slog.e(TAG, "Fail to create new SID for user " + userId);
return;
}
saveSyntheticPasswordHandle(response.getPayload(), userId);
@@ -561,7 +567,7 @@ public class SyntheticPasswordManager {
buffer.put(data, 0, data.length);
buffer.flip();
if (buffer.get() != WEAVER_VERSION) {
- Log.e(TAG, "Invalid weaver slot version of handle " + handle);
+ Slog.e(TAG, "Invalid weaver slot version of handle " + handle);
return INVALID_WEAVER_SLOT;
}
return buffer.getInt();
@@ -580,11 +586,11 @@ public class SyntheticPasswordManager {
if (slot != INVALID_WEAVER_SLOT) {
Set<Integer> usedSlots = getUsedWeaverSlots();
if (!usedSlots.contains(slot)) {
- Log.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
+ Slog.i(TAG, "Destroy weaver slot " + slot + " for user " + userId);
weaverEnroll(slot, null, null);
mPasswordSlotManager.markSlotDeleted(slot);
} else {
- Log.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
+ Slog.w(TAG, "Skip destroying reused weaver slot " + slot + " for user " + userId);
}
}
}
@@ -638,15 +644,9 @@ public class SyntheticPasswordManager {
* @throw IllegalStateException if creation fails.
*/
public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- byte[] credential, int credentialType, AuthenticationToken authToken,
- int requestedQuality, int userId) {
- if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
- credentialType = LockPatternUtils.CREDENTIAL_TYPE_NONE;
- credential = DEFAULT_PASSWORD;
- }
-
+ LockscreenCredential credential, AuthenticationToken authToken, int userId) {
long handle = generateHandle();
- PasswordData pwd = PasswordData.create(credentialType);
+ PasswordData pwd = PasswordData.create(credential.getType());
byte[] pwdToken = computePasswordToken(credential, pwd);
final long sid;
final byte[] applicationId;
@@ -654,7 +654,7 @@ public class SyntheticPasswordManager {
if (isWeaverAvailable()) {
// Weaver based user password
int weaverSlot = getNextAvailableWeaverSlot();
- Log.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
+ Slog.i(TAG, "Weaver enroll password to slot " + weaverSlot + " for user " + userId);
byte[] weaverSecret = weaverEnroll(weaverSlot, passwordTokenToWeaverKey(pwdToken),
null);
if (weaverSecret == null) {
@@ -663,7 +663,8 @@ public class SyntheticPasswordManager {
}
saveWeaverSlot(weaverSlot, handle, userId);
mPasswordSlotManager.markSlotInUse(weaverSlot);
- synchronizeWeaverFrpPassword(pwd, requestedQuality, userId, weaverSlot);
+ // No need to pass in quality since the credential type already encodes sufficient info
+ synchronizeWeaverFrpPassword(pwd, 0, userId, weaverSlot);
pwd.passwordHandle = null;
sid = GateKeeper.INVALID_SECURE_USER_ID;
@@ -674,7 +675,7 @@ public class SyntheticPasswordManager {
try {
gatekeeper.clearSecureUserId(fakeUid(userId));
} catch (RemoteException ignore) {
- Log.w(TAG, "Failed to clear SID from gatekeeper");
+ Slog.w(TAG, "Failed to clear SID from gatekeeper");
}
// GateKeeper based user password
GateKeeperResponse response;
@@ -692,7 +693,8 @@ public class SyntheticPasswordManager {
sid = sidFromPasswordHandle(pwd.passwordHandle);
applicationId = transformUnderSecdiscardable(pwdToken,
createSecdiscardable(handle, userId));
- synchronizeFrpPassword(pwd, requestedQuality, userId);
+ // No need to pass in quality since the credential type already encodes sufficient info
+ synchronizeFrpPassword(pwd, 0, userId);
}
saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
@@ -702,7 +704,7 @@ public class SyntheticPasswordManager {
}
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
- byte[] userCredential, int credentialType,
+ LockscreenCredential userCredential,
ICheckCredentialProgressCallback progressCallback) {
PersistentData persistentData = mStorage.readPersistentDataBlock();
if (persistentData.type == PersistentData.TYPE_SP) {
@@ -714,7 +716,7 @@ public class SyntheticPasswordManager {
response = gatekeeper.verifyChallenge(fakeUid(persistentData.userId),
0 /* challenge */, pwd.passwordHandle, passwordTokenToGkInput(pwdToken));
} catch (RemoteException e) {
- Log.e(TAG, "FRP verifyChallenge failed", e);
+ Slog.e(TAG, "FRP verifyChallenge failed", e);
return VerifyCredentialResponse.ERROR;
}
return VerifyCredentialResponse.fromGateKeeperResponse(response);
@@ -725,7 +727,7 @@ public class SyntheticPasswordManager {
return weaverVerify(weaverSlot, passwordTokenToWeaverKey(pwdToken)).stripPayload();
} else {
- Log.e(TAG, "persistentData.type must be TYPE_SP or TYPE_SP_WEAVER, but is "
+ Slog.e(TAG, "persistentData.type must be TYPE_SP or TYPE_SP_WEAVER, but is "
+ persistentData.type);
return VerifyCredentialResponse.ERROR;
}
@@ -733,11 +735,11 @@ public class SyntheticPasswordManager {
public void migrateFrpPasswordLocked(long handle, UserInfo userInfo, int requestedQuality) {
- if (mStorage.getPersistentDataBlock() != null
+ if (mStorage.getPersistentDataBlockManager() != null
&& LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle,
userInfo.id));
- if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+ if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
int weaverSlot = loadWeaverSlot(handle, userInfo.id);
if (weaverSlot != INVALID_WEAVER_SLOT) {
synchronizeWeaverFrpPassword(pwd, requestedQuality, userInfo.id, weaverSlot);
@@ -750,10 +752,10 @@ public class SyntheticPasswordManager {
private void synchronizeFrpPassword(PasswordData pwd,
int requestedQuality, int userId) {
- if (mStorage.getPersistentDataBlock() != null
+ if (mStorage.getPersistentDataBlockManager() != null
&& LockPatternUtils.userOwnsFrpCredential(mContext,
mUserManager.getUserInfo(userId))) {
- if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+ if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
pwd.toBytes());
} else {
@@ -764,10 +766,10 @@ public class SyntheticPasswordManager {
private void synchronizeWeaverFrpPassword(PasswordData pwd, int requestedQuality, int userId,
int weaverSlot) {
- if (mStorage.getPersistentDataBlock() != null
+ if (mStorage.getPersistentDataBlockManager() != null
&& LockPatternUtils.userOwnsFrpCredential(mContext,
mUserManager.getUserInfo(userId))) {
- if (pwd.passwordType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+ if (pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
requestedQuality, pwd.toBytes());
} else {
@@ -829,14 +831,14 @@ public class SyntheticPasswordManager {
return false;
}
if (!loadEscrowData(authToken, userId)) {
- Log.w(TAG, "User is not escrowable");
+ Slog.w(TAG, "User is not escrowable");
return false;
}
if (isWeaverAvailable()) {
int slot = getNextAvailableWeaverSlot();
- Log.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
+ Slog.i(TAG, "Weaver enroll token to slot " + slot + " for user " + userId);
if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
- Log.e(TAG, "Failed to enroll weaver secret when activating token");
+ Slog.e(TAG, "Failed to enroll weaver secret when activating token");
return false;
}
saveWeaverSlot(slot, handle, userId);
@@ -881,18 +883,20 @@ public class SyntheticPasswordManager {
* Decrypt a synthetic password by supplying the user credential and corresponding password
* blob handle generated previously. If the decryption is successful, initiate a GateKeeper
* verification to referesh the SID & Auth token maintained by the system.
- * Note: the credential type is not validated here since there are call sites where the type is
- * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
*/
public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- long handle, byte[] credential, int userId,
+ long handle, @NonNull LockscreenCredential credential, int userId,
ICheckCredentialProgressCallback progressCallback) {
- if (credential == null) {
- credential = DEFAULT_PASSWORD;
- }
AuthenticationResult result = new AuthenticationResult();
PasswordData pwd = PasswordData.fromBytes(loadState(PASSWORD_DATA_NAME, handle, userId));
- result.credentialType = pwd.passwordType;
+
+ if (!credential.checkAgainstStoredType(pwd.credentialType)) {
+ Slog.e(TAG, String.format("Credential type mismatch: expected %d actual %d",
+ pwd.credentialType, credential.getType()));
+ result.gkResponse = VerifyCredentialResponse.ERROR;
+ return result;
+ }
+
byte[] pwdToken = computePasswordToken(credential, pwd);
final byte[] applicationId;
@@ -901,7 +905,7 @@ public class SyntheticPasswordManager {
if (weaverSlot != INVALID_WEAVER_SLOT) {
// Weaver based user password
if (!isWeaverAvailable()) {
- Log.e(TAG, "No weaver service to unwrap password based SP");
+ Slog.e(TAG, "No weaver service to unwrap password based SP");
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
@@ -918,7 +922,7 @@ public class SyntheticPasswordManager {
response = gatekeeper.verifyChallenge(fakeUid(userId), 0L,
pwd.passwordHandle, gkPwdToken);
} catch (RemoteException e) {
- Log.e(TAG, "gatekeeper verify failed", e);
+ Slog.e(TAG, "gatekeeper verify failed", e);
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
@@ -931,21 +935,19 @@ public class SyntheticPasswordManager {
reenrollResponse = gatekeeper.enroll(fakeUid(userId),
pwd.passwordHandle, gkPwdToken, gkPwdToken);
} catch (RemoteException e) {
- Log.w(TAG, "Fail to invoke gatekeeper.enroll", e);
+ Slog.w(TAG, "Fail to invoke gatekeeper.enroll", e);
reenrollResponse = GateKeeperResponse.ERROR;
// continue the flow anyway
}
if (reenrollResponse.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
pwd.passwordHandle = reenrollResponse.getPayload();
+ // Use the reenrollment opportunity to update credential type
+ // (getting rid of CREDENTIAL_TYPE_PASSWORD_OR_PIN)
+ pwd.credentialType = credential.getType();
saveState(PASSWORD_DATA_NAME, pwd.toBytes(), handle, userId);
- synchronizeFrpPassword(pwd,
- pwd.passwordType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
- ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
- : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
- /* TODO(roosa): keep the same password quality */,
- userId);
+ synchronizeFrpPassword(pwd, 0, userId);
} else {
- Log.w(TAG, "Fail to re-enroll user password for user " + userId);
+ Slog.w(TAG, "Fail to re-enroll user password for user " + userId);
// continue the flow anyway
}
}
@@ -966,7 +968,7 @@ public class SyntheticPasswordManager {
try {
progressCallback.onCredentialVerified();
} catch (RemoteException e) {
- Log.w(TAG, "progressCallback throws exception", e);
+ Slog.w(TAG, "progressCallback throws exception", e);
}
}
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
@@ -989,14 +991,14 @@ public class SyntheticPasswordManager {
int slotId = loadWeaverSlot(handle, userId);
if (slotId != INVALID_WEAVER_SLOT) {
if (!isWeaverAvailable()) {
- Log.e(TAG, "No weaver service to unwrap token based SP");
+ Slog.e(TAG, "No weaver service to unwrap token based SP");
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
VerifyCredentialResponse response = weaverVerify(slotId, null);
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK ||
response.getPayload() == null) {
- Log.e(TAG, "Failed to retrieve weaver secret when unwrapping token");
+ Slog.e(TAG, "Failed to retrieve weaver secret when unwrapping token");
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
@@ -1043,13 +1045,13 @@ public class SyntheticPasswordManager {
Arrays.copyOfRange(blob, 2, blob.length), applicationId);
}
if (secret == null) {
- Log.e(TAG, "Fail to decrypt SP for user " + userId);
+ Slog.e(TAG, "Fail to decrypt SP for user " + userId);
return null;
}
AuthenticationToken result = new AuthenticationToken(version);
if (type == SYNTHETIC_PASSWORD_TOKEN_BASED) {
if (!loadEscrowData(result, userId)) {
- Log.e(TAG, "User is not escrowable: " + userId);
+ Slog.e(TAG, "User is not escrowable: " + userId);
return null;
}
result.recreate(secret);
@@ -1057,7 +1059,7 @@ public class SyntheticPasswordManager {
result.syntheticPassword = new String(secret);
}
if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
- Log.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
+ Slog.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
}
return result;
@@ -1084,7 +1086,7 @@ public class SyntheticPasswordManager {
response = gatekeeper.verifyChallenge(userId, challenge,
spHandle, auth.deriveGkPassword());
} catch (RemoteException e) {
- Log.e(TAG, "Fail to verify with gatekeeper " + userId, e);
+ Slog.e(TAG, "Fail to verify with gatekeeper " + userId, e);
return VerifyCredentialResponse.ERROR;
}
int responseCode = response.getResponseCode();
@@ -1095,7 +1097,7 @@ public class SyntheticPasswordManager {
response = gatekeeper.enroll(userId, spHandle, spHandle,
auth.deriveGkPassword());
} catch (RemoteException e) {
- Log.e(TAG, "Failed to invoke gatekeeper.enroll", e);
+ Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e);
response = GateKeeperResponse.ERROR;
}
if (response.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
@@ -1105,7 +1107,7 @@ public class SyntheticPasswordManager {
return verifyChallenge(gatekeeper, auth, challenge, userId);
} else {
// Fall through, return result from the previous verification attempt.
- Log.w(TAG, "Fail to re-enroll SP handle for user " + userId);
+ Slog.w(TAG, "Fail to re-enroll SP handle for user " + userId);
}
}
return result;
@@ -1225,7 +1227,8 @@ public class SyntheticPasswordManager {
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
}
- private byte[] computePasswordToken(byte[] password, PasswordData data) {
+ private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) {
+ final byte[] password = credential.isNone() ? DEFAULT_PASSWORD : credential.getCredential();
return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
PASSWORD_TOKEN_LENGTH);
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 5676da213dd2..29338ba06dc2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -18,7 +18,6 @@ package com.android.server.locksettings.recoverablekeystore;
import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_LOCKSCREEN;
-import android.annotation.Nullable;
import android.content.Context;
import android.os.RemoteException;
import android.security.Scrypt;
@@ -193,6 +192,7 @@ public class KeySyncTask implements Runnable {
private boolean isCustomLockScreen() {
return mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE
&& mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PATTERN
+ && mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PIN
&& mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
@@ -345,7 +345,7 @@ public class KeySyncTask implements Runnable {
}
KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder()
.setUserSecretType(TYPE_LOCKSCREEN)
- .setLockScreenUiFormat(getUiFormat(mCredentialType, mCredential))
+ .setLockScreenUiFormat(getUiFormat(mCredentialType))
.setKeyDerivationParams(keyDerivationParams)
.setSecret(new byte[0])
.build();
@@ -449,11 +449,10 @@ public class KeySyncTask implements Runnable {
* @return The format - either pattern, pin, or password.
*/
@VisibleForTesting
- @KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(
- int credentialType, byte[] credential) {
+ @KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(int credentialType) {
if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
return KeyChainProtectionParams.UI_FORMAT_PATTERN;
- } else if (isPin(credential)) {
+ } else if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PIN) {
return KeyChainProtectionParams.UI_FORMAT_PIN;
} else {
return KeyChainProtectionParams.UI_FORMAT_PASSWORD;
@@ -472,23 +471,6 @@ public class KeySyncTask implements Runnable {
}
/**
- * Returns {@code true} if {@code credential} looks like a pin.
- */
- @VisibleForTesting
- static boolean isPin(@Nullable byte[] credential) {
- if (credential == null) {
- return false;
- }
- int length = credential.length;
- for (int i = 0; i < length; i++) {
- if (!Character.isDigit((char) credential[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
* Hashes {@code credentials} with the given {@code salt}.
*
* @return The SHA-256 hash.
@@ -541,6 +523,7 @@ public class KeySyncTask implements Runnable {
}
private boolean shouldUseScryptToHashCredential() {
- return mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+ return mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
+ || mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_PIN;
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
index 90a36723de4d..c963f799245f 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -97,7 +97,8 @@ public class TestOnlyInsecureCertificateHelper {
if (credential == null) {
return false;
}
- if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
+ && credentialType != LockPatternUtils.CREDENTIAL_TYPE_PIN) {
return false;
}
byte[] insecurePasswordPrefixBytes =
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 714bbb97c90d..9a1b30dc2b0b 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -25,7 +25,6 @@ import android.os.Binder;
import android.os.BugreportParams;
import android.os.IDumpstate;
import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -64,13 +63,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
@Override
@RequiresPermission(android.Manifest.permission.DUMP)
- public IDumpstateToken setListener(String name, IDumpstateListener listener,
- boolean getSectionDetails) {
- throw new UnsupportedOperationException("setListener is not allowed on this service");
- }
-
- @Override
- @RequiresPermission(android.Manifest.permission.DUMP)
public void startBugreport(int callingUidUnused, String callingPackage,
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
int bugreportMode, IDumpstateListener listener) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0a4415bf0436..104ce1cbd5cd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1562,8 +1562,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Send broadcasts
for (int i = 0; i < size; i++) {
- sendPackageChangedBroadcast(packages[i], true, components[i], uids[i],
- null);
+ sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+ components[i], uids[i], null /* reason */);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
@@ -2049,7 +2049,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0; i < res.libraryConsumers.size(); i++) {
PackageParser.Package pkg = res.libraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
- sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/,
+ sendPackageChangedBroadcast(pkg.packageName, false /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.packageName)),
pkg.applicationInfo.uid, null);
}
@@ -19999,7 +19999,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private void sendPackageChangedBroadcast(String packageName,
- boolean killFlag, ArrayList<String> componentNames, int packageUid,
+ boolean dontKillApp, ArrayList<String> componentNames, int packageUid,
String reason) {
if (DEBUG_INSTALL)
Log.v(TAG, "Sending package changed: package=" + packageName + " components="
@@ -20009,7 +20009,7 @@ public class PackageManagerService extends IPackageManager.Stub
String nameList[] = new String[componentNames.size()];
componentNames.toArray(nameList);
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
- extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
+ extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp);
extras.putInt(Intent.EXTRA_UID, packageUid);
if (reason != null) {
extras.putString(Intent.EXTRA_REASON, reason);
@@ -20282,7 +20282,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
sendPackageChangedBroadcast(pkg.packageName,
- false /* killFlag */,
+ true /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.packageName)),
pkg.applicationInfo.uid,
Intent.ACTION_OVERLAY_CHANGED);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2593c38180e2..5e1d93fdda3d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -386,6 +386,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
BurnInProtectionHelper mBurnInProtectionHelper;
private DisplayFoldController mDisplayFoldController;
AppOpsManager mAppOpsManager;
+ PackageManager mPackageManager;
private boolean mHasFeatureAuto;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
@@ -1555,10 +1556,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void launchAllAppsAction() {
Intent intent = new Intent(Intent.ACTION_ALL_APPS);
if (mHasFeatureLeanback) {
- final PackageManager pm = mContext.getPackageManager();
Intent intentLauncher = new Intent(Intent.ACTION_MAIN);
intentLauncher.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = pm.resolveActivityAsUser(intentLauncher,
+ ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(intentLauncher,
PackageManager.MATCH_SYSTEM_ONLY,
mCurrentUserId);
if (resolveInfo != null) {
@@ -1753,10 +1753,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
- mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
- mHasFeatureAuto = mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE);
- mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
+ mPackageManager = mContext.getPackageManager();
+ mHasFeatureWatch = mPackageManager.hasSystemFeature(FEATURE_WATCH);
+ mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK);
+ mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE);
+ mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC);
mAccessibilityShortcutController =
new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
mLogger = new MetricsLogger();
@@ -1994,7 +1995,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
- if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
+ if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
}
}
@@ -2138,7 +2139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ApplicationInfo appInfo;
try {
- appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
+ appInfo = mPackageManager.getApplicationInfoAsUser(
attrs.packageName,
0 /* flags */,
UserHandle.getUserId(callingUid));
@@ -4914,7 +4915,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override public void run() {
if (mBootMsgDialog == null) {
int theme;
- if (mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK)) {
+ if (mPackageManager.hasSystemFeature(FEATURE_LEANBACK)) {
theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
} else {
theme = 0;
@@ -4943,7 +4944,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return true;
}
};
- if (mContext.getPackageManager().isDeviceUpgrading()) {
+ if (mPackageManager.isDeviceUpgrading()) {
mBootMsgDialog.setTitle(R.string.android_upgrading_title);
} else {
mBootMsgDialog.setTitle(R.string.android_start_title);
@@ -5203,7 +5204,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
ActivityInfo ai = null;
- ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
+ ResolveInfo info = mPackageManager.resolveActivityAsUser(
intent,
PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
mCurrentUserId);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index edf0cbfe459a..b67d9b285acd 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -94,16 +94,16 @@ public class Notifier {
private static final int MSG_PROFILE_TIMED_OUT = 5;
private static final int MSG_WIRED_CHARGING_STARTED = 6;
- private static final long[] WIRELESS_VIBRATION_TIME = {
+ private static final long[] CHARGING_VIBRATION_TIME = {
40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
40, 40, 40, 40, 40, 40, 40 // ramp-down sampling rate = 40ms
};
- private static final int[] WIRELESS_VIBRATION_AMPLITUDE = {
+ private static final int[] CHARGING_VIBRATION_AMPLITUDE = {
1, 4, 11, 25, 44, 67, 91, 114, 123, // ramp-up amplitude (from 0 to 50%)
103, 79, 55, 34, 17, 7, 2 // ramp-up amplitude
};
- private static final VibrationEffect WIRELESS_CHARGING_VIBRATION_EFFECT =
- VibrationEffect.createWaveform(WIRELESS_VIBRATION_TIME, WIRELESS_VIBRATION_AMPLITUDE,
+ private static final VibrationEffect CHARGING_VIBRATION_EFFECT =
+ VibrationEffect.createWaveform(CHARGING_VIBRATION_TIME, CHARGING_VIBRATION_AMPLITUDE,
-1);
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -130,6 +130,10 @@ public class Notifier {
// True if the device should suspend when the screen is off due to proximity.
private final boolean mSuspendWhenScreenOffDueToProximityConfig;
+ // True if the device should show the wireless charging animation when the device
+ // begins charging wirelessly
+ private final boolean mShowWirelessChargingAnimationConfig;
+
// The current interactive state. This is set as soon as an interactive state
// transition begins so as to capture the reason that it happened. At some point
// this state will propagate to the pending state then eventually to the
@@ -182,6 +186,8 @@ public class Notifier {
mSuspendWhenScreenOffDueToProximityConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
+ mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
// Initialize interactive state for battery stats.
try {
@@ -755,35 +761,45 @@ public class Notifier {
}
};
- /**
- * If enabled, plays a sound and/or vibration when wireless or non-wireless charging has started
- */
- private void playChargingStartedFeedback(@UserIdInt int userId) {
- playChargingStartedVibration(userId);
+ private void playChargingStartedFeedback(@UserIdInt int userId, boolean wireless) {
+ if (!isChargingFeedbackEnabled(userId)) {
+ return;
+ }
+
+ // vibrate
+ final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
+ if (vibrate) {
+ mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
+ }
+
+ // play sound
final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.CHARGING_STARTED_SOUND);
- if (isChargingFeedbackEnabled(userId) && soundPath != null) {
- final Uri soundUri = Uri.parse("file://" + soundPath);
- if (soundUri != null) {
- final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
- if (sfx != null) {
- sfx.setStreamType(AudioManager.STREAM_SYSTEM);
- sfx.play();
- }
+ wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND
+ : Settings.Global.CHARGING_STARTED_SOUND);
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
}
}
}
private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) {
- playChargingStartedFeedback(userId);
- if (mStatusBarManagerInternal != null) {
+ // play sounds + haptics
+ playChargingStartedFeedback(userId, true /* wireless */);
+
+ // show animation
+ if (mShowWirelessChargingAnimationConfig && mStatusBarManagerInternal != null) {
mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
}
mSuspendBlocker.release();
}
private void showWiredChargingStarted(@UserIdInt int userId) {
- playChargingStartedFeedback(userId);
+ playChargingStartedFeedback(userId, false /* wireless */);
mSuspendBlocker.release();
}
@@ -791,14 +807,6 @@ public class Notifier {
mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
}
- private void playChargingStartedVibration(@UserIdInt int userId) {
- final boolean vibrateEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
- if (vibrateEnabled && isChargingFeedbackEnabled(userId)) {
- mVibrator.vibrate(WIRELESS_CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
- }
- }
-
private boolean isChargingFeedbackEnabled(@UserIdInt int userId) {
final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.CHARGING_SOUNDS_ENABLED, 1, userId) != 0;
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index e4cb19e3eb21..e72ba8d9f01b 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -17,6 +17,7 @@
package com.android.server.twilight;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -160,8 +161,13 @@ public final class TwilightService extends SystemService
// Request the device's location immediately if a previous location isn't available.
if (mLocationManager.getLastLocation() == null) {
if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
- mLocationManager.requestSingleUpdate(
- LocationManager.NETWORK_PROVIDER, this, Looper.getMainLooper());
+ mLocationManager.getCurrentLocation(
+ LocationManager.NETWORK_PROVIDER, null, getContext().getMainExecutor(),
+ this::onLocationChanged);
+ } else if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+ mLocationManager.getCurrentLocation(
+ LocationManager.GPS_PROVIDER, null, getContext().getMainExecutor(),
+ this::onLocationChanged);
}
}
@@ -218,12 +224,7 @@ public final class TwilightService extends SystemService
for (int i = mListeners.size() - 1; i >= 0; --i) {
final TwilightListener listener = mListeners.keyAt(i);
final Handler handler = mListeners.valueAt(i);
- handler.post(new Runnable() {
- @Override
- public void run() {
- listener.onTwilightStateChanged(state);
- }
- });
+ handler.post(() -> listener.onTwilightStateChanged(state));
}
}
}
@@ -243,12 +244,8 @@ public final class TwilightService extends SystemService
}
@Override
- public void onLocationChanged(Location location) {
- // Location providers may erroneously return (0.0, 0.0) when they fail to determine the
- // device's location. These location updates can be safely ignored since the chance of a
- // user actually being at these coordinates is quite low.
- if (location != null
- && !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
+ public void onLocationChanged(@Nullable Location location) {
+ if (location != null) {
Slog.d(TAG, "onLocationChanged:"
+ " provider=" + location.getProvider()
+ " accuracy=" + location.getAccuracy()
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index e6c6b12e18c6..9d41d97bc1ed 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -187,9 +187,22 @@ class ActivityMetricsLogger {
private int startingWindowDelayMs = INVALID_DELAY;
private int bindApplicationDelayMs = INVALID_DELAY;
private int reason = APP_TRANSITION_TIMEOUT;
- private boolean loggedWindowsDrawn;
+ // TODO(b/132736359) The number may need to consider the visibility change.
+ private int numUndrawnActivities = 1;
private boolean loggedStartingWindowDrawn;
private boolean launchTraceActive;
+
+ /**
+ * Remembers the latest launched activity to represent the final transition. This also
+ * increments the number of activities that should be drawn, so a consecutive launching
+ * sequence can be coalesced as one event.
+ */
+ void setLatestLaunchedActivity(ActivityRecord r) {
+ if (launchedActivity == r) {
+ return;
+ }
+ launchedActivity = r;
+ }
}
final class WindowingModeTransitionInfoSnapshot {
@@ -400,7 +413,7 @@ class ActivityMetricsLogger {
// the other attributes.
// Coalesce multiple (trampoline) activities from a single sequence together.
- info.launchedActivity = launchedActivity;
+ info.setLatestLaunchedActivity(launchedActivity);
return;
}
@@ -422,7 +435,7 @@ class ActivityMetricsLogger {
// A new launch sequence [with the windowingMode] has begun.
// Start tracking it.
final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
- newInfo.launchedActivity = launchedActivity;
+ newInfo.setLatestLaunchedActivity(launchedActivity);
newInfo.currentTransitionProcessRunning = processRunning;
newInfo.startResult = resultCode;
mWindowingModeTransitionInfo.put(windowingMode, newInfo);
@@ -448,11 +461,11 @@ class ActivityMetricsLogger {
if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
- if (info == null || info.loggedWindowsDrawn) {
+ if (info == null || info.numUndrawnActivities == 0) {
return null;
}
info.windowsDrawnDelayMs = calculateDelay(timestampNs);
- info.loggedWindowsDrawn = true;
+ info.numUndrawnActivities--;
final WindowingModeTransitionInfoSnapshot infoSnapshot =
new WindowingModeTransitionInfoSnapshot(info);
if (allWindowsDrawn() && mLoggedTransitionStarting) {
@@ -594,9 +607,10 @@ class ActivityMetricsLogger {
}
}
- private boolean allWindowsDrawn() {
+ @VisibleForTesting
+ boolean allWindowsDrawn() {
for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
- if (!mWindowingModeTransitionInfo.valueAt(index).loggedWindowsDrawn) {
+ if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) {
return false;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 208f54c146ae..a783ee9d4e44 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -876,6 +876,8 @@ public class DisplayPolicy {
if (canToastShowWhenLocked(callingPid)) {
attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
}
+ // Toasts can't be clickable
+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
break;
}
@@ -3241,7 +3243,8 @@ public class DisplayPolicy {
statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive);
// TODO(b/118118435): Remove this after removing system UI visibilities.
- mDisplayContent.statusBarVisibilityChanged(visibility);
+ mDisplayContent.statusBarVisibilityChanged(
+ visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE));
}
});
return diff;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c4adc035d613..5e49c7a9e5d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -168,6 +168,7 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
@@ -1959,6 +1960,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(ConnectivityManager.class);
}
+ LocationManager getLocationManager() {
+ return mContext.getSystemService(LocationManager.class);
+ }
+
IWindowManager getIWindowManager() {
return IWindowManager.Stub
.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -4178,7 +4183,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) {
try {
return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY,
- packageName);
+ packageName, userId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
}
@@ -10899,6 +10904,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ int userId = mInjector.userHandleGetCallingUserId();
+
+ synchronized (getLockObject()) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ if (!isDeviceOwner(who, userId) && !isCurrentUserDemo()) {
+ throw new SecurityException(
+ "Permission denial: Profile owners cannot update location settings");
+ }
+ }
+
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.getLocationManager().setLocationEnabledForUser(
+ locationEnabled, UserHandle.of(userId));
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
+ .setAdmin(who)
+ .setStrings(Settings.Secure.LOCATION_MODE, Integer.toString(
+ locationEnabled ? Settings.Secure.LOCATION_MODE_ON
+ : Settings.Secure.LOCATION_MODE_OFF))
+ .write();
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
public boolean setTime(ComponentName who, long millis) {
Preconditions.checkNotNull(who, "ComponentName is null in setTime");
enforceDeviceOwner(who);
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 537287d18cca..98630576ed66 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -52,6 +52,7 @@ import android.test.AndroidTestCase;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockSettingsInternal;
+import com.android.internal.widget.LockscreenCredential;
import com.android.server.LocalServices;
import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
import com.android.server.wm.WindowManagerInternal;
@@ -104,6 +105,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
FaceManager mFaceManager;
PackageManager mPackageManager;
protected boolean mHasSecureLockScreen;
+ FakeSettings mSettings;
@Override
protected void setUp() throws Exception {
@@ -125,6 +127,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
mFingerprintManager = mock(FingerprintManager.class);
mFaceManager = mock(FaceManager.class);
mPackageManager = mock(PackageManager.class);
+ mSettings = new FakeSettings();
LocalServices.removeServiceForTest(LockSettingsInternal.class);
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -162,7 +165,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager,
- mUserManagerInternal, mDeviceStateCache);
+ mUserManagerInternal, mDeviceStateCache, mSettings);
when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
installChildProfile(MANAGED_PROFILE_USER_ID);
@@ -195,6 +198,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID);
mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID);
+ mSettings.setDeviceProvisioned(true);
mLocalService = LocalServices.getService(LockSettingsInternal.class);
}
@@ -307,4 +311,22 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
protected static void assertArrayNotEquals(byte[] expected, byte[] actual) {
assertFalse(Arrays.equals(expected, actual));
}
+
+ protected LockscreenCredential newPassword(String password) {
+ return LockscreenCredential.createPasswordOrNone(password);
+ }
+
+ protected LockscreenCredential newPin(String pin) {
+ return LockscreenCredential.createPinOrNone(pin);
+ }
+
+ protected LockscreenCredential newPattern(String pattern) {
+ return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
+ pattern.getBytes()));
+ }
+
+ protected LockscreenCredential nonePassword() {
+ return LockscreenCredential.createNone();
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
index d2a914527880..5c54883c338f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
@@ -15,9 +15,6 @@
*/
package com.android.server.locksettings;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.mockito.Mockito.anyInt;
@@ -30,7 +27,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import org.mockito.ArgumentCaptor;
@@ -59,56 +56,53 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
}
public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
- final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
- final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
+ final LockscreenCredential password = newPassword("password");
+ final LockscreenCredential newPassword = newPassword("newpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, true);
+ mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, true);
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
+ false);
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ newPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
- final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
- final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
+ final LockscreenCredential password = newPassword("password");
+ final LockscreenCredential newPassword = newPassword("newpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
+ mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
+ true);
assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// Verify the password
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ newPassword, 0, PRIMARY_USER_ID).getResponseCode());
}
public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
- final byte[] password =
- "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
- final byte[] newPassword =
- "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
+ final LockscreenCredential password = newPassword("password");
+ final LockscreenCredential newPassword = newPassword("newpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
+ mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
+ true);
// Verify the password
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ newPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
// Ensure the same secret was passed each time
@@ -118,31 +112,30 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
}
public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
- final byte[] password =
- "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
- final byte[] newPassword =
- "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
+ final LockscreenCredential password = newPassword("password");
+ final LockscreenCredential newPassword = newPassword("newpassword");
// Disable caching for this test
enableSpCaching(false);
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+ flushHandlerTasks();
+
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
assertExpectException(
IllegalStateException.class,
/* messageRegex= */ "Untrusted credential reset not possible without cached SP",
- () -> mService.setLockCredential(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true));
+ () -> mService.setLockCredential(newPassword, nonePassword(),
+ PRIMARY_USER_ID, true));
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// Verify the new password doesn't work but the old one still does
- assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
+ newPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java
new file mode 100644
index 000000000000..70a927c216ec
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java
@@ -0,0 +1,36 @@
+/*
+ * 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.locksettings;
+
+import android.provider.Settings;
+
+public class FakeSettings {
+
+ private int mDeviceProvisioned;
+
+ public void setDeviceProvisioned(boolean provisioned) {
+ mDeviceProvisioned = provisioned ? 1 : 0;
+ }
+
+ public int globalGetInt(String keyName) {
+ switch (keyName) {
+ case Settings.Global.DEVICE_PROVISIONED:
+ return mDeviceProvisioned;
+ default:
+ throw new IllegalArgumentException("Unhandled global settings: " + keyName);
+ }
+ }
+}
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 fcd98e0742ea..7e7e170fee06 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -20,9 +20,11 @@ import static org.mockito.Mockito.mock;
import android.app.IActivityManager;
import android.app.admin.DeviceStateCache;
+import android.content.ContentResolver;
import android.content.Context;
import android.hardware.authsecret.V1_0.IAuthSecret;
import android.os.Handler;
+import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserManagerInternal;
@@ -31,6 +33,7 @@ import android.security.KeyStore;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.server.ServiceThread;
import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
@@ -50,12 +53,14 @@ public class LockSettingsServiceTestable extends LockSettingsService {
private RecoverableKeyStoreManager mRecoverableKeyStoreManager;
private UserManagerInternal mUserManagerInternal;
private DeviceStateCache mDeviceStateCache;
+ private FakeSettings mSettings;
public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
IActivityManager activityManager, LockPatternUtils lockPatternUtils,
IStorageManager storageManager, SyntheticPasswordManager spManager,
FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
- UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
+ UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
+ FakeSettings settings) {
super(context);
mLockSettingsStorage = storage;
mKeyStore = keyStore;
@@ -67,6 +72,7 @@ public class LockSettingsServiceTestable extends LockSettingsService {
mRecoverableKeyStoreManager = recoverableKeyStoreManager;
mUserManagerInternal = userManagerInternal;
mDeviceStateCache = deviceStateCache;
+ mSettings = settings;
}
@Override
@@ -119,6 +125,12 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
+ public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
+ int defaultValue) {
+ return mSettings.globalGetInt(keyName);
+ }
+
+ @Override
public UserManagerInternal getUserManagerInternal() {
return mUserManagerInternal;
}
@@ -144,27 +156,33 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
}
+ public MockInjector mInjector;
+
protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils,
LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore,
IStorageManager storageManager, IActivityManager mActivityManager,
SyntheticPasswordManager spManager, IAuthSecret authSecretService,
FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
- UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
+ UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
+ FakeSettings settings) {
super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils,
storageManager, spManager, gsiService,
- recoverableKeyStoreManager, userManagerInternal, deviceStateCache));
+ recoverableKeyStoreManager, userManagerInternal, deviceStateCache, settings));
mGateKeeperService = gatekeeper;
mAuthSecretService = authSecretService;
}
@Override
- protected void tieProfileLockToParent(int userId, byte[] password) {
- mStorage.writeChildProfileLock(userId, password);
+ protected void tieProfileLockToParent(int userId, LockscreenCredential password) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeParcelable(password, 0);
+ mStorage.writeChildProfileLock(userId, parcel.marshall());
+ parcel.recycle();
}
@Override
- protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
- KeyPermanentlyInvalidatedException {
+ protected LockscreenCredential getDecryptedPasswordForTiedProfile(int userId)
+ throws FileNotFoundException, KeyPermanentlyInvalidatedException {
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
throw new FileNotFoundException("Child profile lock file not found");
@@ -176,6 +194,13 @@ public class LockSettingsServiceTestable extends LockSettingsService {
} catch (RemoteException e) {
// shouldn't happen.
}
- return storedData;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.unmarshall(storedData, 0, storedData.length);
+ parcel.setDataPosition(0);
+ return (LockscreenCredential) parcel.readParcelable(null);
+ } finally {
+ parcel.recycle();
+ }
}
}
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 5818133aa2a4..86ef31a392b5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -16,14 +16,10 @@
package com.android.server.locksettings;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -39,6 +35,7 @@ import android.service.gatekeeper.GateKeeperResponse;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
@@ -61,60 +58,51 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
}
public void testCreatePasswordPrimaryUser() throws RemoteException {
- testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD,
- PASSWORD_QUALITY_ALPHABETIC);
+ testCreateCredential(PRIMARY_USER_ID, newPassword("password"));
}
public void testCreatePasswordFailsWithoutLockScreen() throws RemoteException {
- testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "password",
- CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
+ testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, newPassword("password"));
}
public void testCreatePatternPrimaryUser() throws RemoteException {
- testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN,
- PASSWORD_QUALITY_SOMETHING);
+ testCreateCredential(PRIMARY_USER_ID, newPattern("123456789"));
}
public void testCreatePatternFailsWithoutLockScreen() throws RemoteException {
- testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "123456789",
- CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
+ testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, newPattern("123456789"));
}
public void testChangePasswordPrimaryUser() throws RemoteException {
- testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
- "asdfghjk", CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
+ testChangeCredentials(PRIMARY_USER_ID, newPattern("78963214"), newPassword("asdfghjk"));
}
public void testChangePatternPrimaryUser() throws RemoteException {
- testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
- "1596321", CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
+ testChangeCredentials(PRIMARY_USER_ID, newPassword("!£$%^&*(())"), newPattern("1596321"));
}
public void testChangePasswordFailPrimaryUser() throws RemoteException {
final long sid = 1234;
- initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
+ initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid);
- assertFalse(mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
- "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false));
- assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
+ assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"),
+ PRIMARY_USER_ID, false));
+ assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid);
}
public void testClearPasswordPrimaryUser() throws RemoteException {
- final String PASSWORD = "password";
- initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
- assertTrue(mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false));
- assertFalse(mService.havePassword(PRIMARY_USER_ID));
- assertFalse(mService.havePattern(PRIMARY_USER_ID));
+ initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234);
+ assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
+ PRIMARY_USER_ID, false));
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testManagedProfileUnifiedChallenge() throws RemoteException {
- final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
- final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
- assertTrue(mService.setLockCredential(firstUnifiedPassword.getBytes(),
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false));
+ final LockscreenCredential firstUnifiedPassword = newPassword("pwd-1");
+ final LockscreenCredential secondUnifiedPassword = newPassword("pwd-2");
+ assertTrue(mService.setLockCredential(firstUnifiedPassword,
+ nonePassword(), PRIMARY_USER_ID, false));
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
@@ -132,8 +120,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
// verify credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
- PRIMARY_USER_ID).getResponseCode());
+ firstUnifiedPassword, 0, PRIMARY_USER_ID)
+ .getResponseCode());
// Verify that we have a new auth token for the profile
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
@@ -148,16 +136,15 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
*/
mStorageManager.setIgnoreBadUnlock(true);
// Change primary password and verify that profile SID remains
- assertTrue(mService.setLockCredential(secondUnifiedPassword.getBytes(),
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, firstUnifiedPassword.getBytes(),
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false));
+ assertTrue(mService.setLockCredential(
+ secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID, false));
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
// Clear unified challenge
- assertTrue(mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID,
+ assertTrue(mService.setLockCredential(nonePassword(),
+ secondUnifiedPassword, PRIMARY_USER_ID,
false));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
@@ -165,19 +152,19 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
}
public void testManagedProfileSeparateChallenge() throws RemoteException {
- final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
- final String profilePassword = "testManagedProfileSeparateChallenge-profile";
- assertTrue(mService.setLockCredential(primaryPassword.getBytes(),
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false));
+ final LockscreenCredential primaryPassword = newPassword("primary");
+ final LockscreenCredential profilePassword = newPassword("profile");
+ assertTrue(mService.setLockCredential(primaryPassword,
+ nonePassword(),
+ PRIMARY_USER_ID, false));
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
* credential as part of verifyCredential() before the new credential is committed in
* StorageManager. So we relax the check in our mock StorageManager to allow that.
*/
mStorageManager.setIgnoreBadUnlock(true);
- assertTrue(mService.setLockCredential(profilePassword.getBytes(),
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID, false));
+ assertTrue(mService.setLockCredential(profilePassword,
+ nonePassword(),
+ MANAGED_PROFILE_USER_ID, false));
mStorageManager.setIgnoreBadUnlock(false);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
@@ -190,81 +177,69 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
// verify primary credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
- PRIMARY_USER_ID).getResponseCode());
+ primaryPassword, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
// verify profile credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
- MANAGED_PROFILE_USER_ID).getResponseCode());
+ profilePassword, 0, MANAGED_PROFILE_USER_ID)
+ .getResponseCode());
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
// Change primary credential and make sure we don't affect profile
mStorageManager.setIgnoreBadUnlock(true);
- assertTrue(mService.setLockCredential("pwd".getBytes(),
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false));
+ assertTrue(mService.setLockCredential(
+ newPassword("pwd"), primaryPassword, PRIMARY_USER_ID, false));
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
- MANAGED_PROFILE_USER_ID).getResponseCode());
+ profilePassword, 0, MANAGED_PROFILE_USER_ID)
+ .getResponseCode());
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
}
public void testSetLockCredential_forPrimaryUser_sendsCredentials() throws Exception {
- final byte[] password = "password".getBytes();
-
assertTrue(mService.setLockCredential(
- password,
- CREDENTIAL_TYPE_PASSWORD,
- null,
- PASSWORD_QUALITY_ALPHABETIC,
+ newPassword("password"),
+ nonePassword(),
PRIMARY_USER_ID,
false));
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, password, PRIMARY_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "password".getBytes(),
+ PRIMARY_USER_ID);
}
public void testSetLockCredential_forProfileWithSeparateChallenge_sendsCredentials()
throws Exception {
- final byte[] pattern = "12345".getBytes();
-
assertTrue(mService.setLockCredential(
- pattern,
- CREDENTIAL_TYPE_PATTERN,
- null,
- PASSWORD_QUALITY_SOMETHING,
+ newPattern("12345"),
+ nonePassword(),
MANAGED_PROFILE_USER_ID,
false));
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, "12345".getBytes(),
+ MANAGED_PROFILE_USER_ID);
}
public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
throws Exception {
- final String oldCredential = "12345";
- final byte[] newCredential = "newPassword".getBytes();
initializeStorageWithCredential(
MANAGED_PROFILE_USER_ID,
- oldCredential,
- CREDENTIAL_TYPE_PATTERN,
- PASSWORD_QUALITY_SOMETHING);
+ newPattern("12345"),
+ 1234);
assertTrue(mService.setLockCredential(
- newCredential,
- CREDENTIAL_TYPE_PASSWORD,
- oldCredential.getBytes(),
- PASSWORD_QUALITY_ALPHABETIC,
+ newPassword("newPassword"),
+ newPattern("12345"),
MANAGED_PROFILE_USER_ID,
false));
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(
- CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "newPassword".getBytes(),
+ MANAGED_PROFILE_USER_ID);
}
public void testSetLockCredential_forProfileWithUnifiedChallenge_doesNotSendRandomCredential()
@@ -272,10 +247,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertTrue(mService.setLockCredential(
- "12345".getBytes(),
- CREDENTIAL_TYPE_PATTERN,
- null,
- PASSWORD_QUALITY_SOMETHING,
+ newPattern("12345"),
+ nonePassword(),
PRIMARY_USER_ID,
false));
@@ -287,40 +260,35 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
public void
testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_updatesBothCredentials()
throws Exception {
- final String oldCredential = "oldPassword";
- final byte[] newCredential = "newPassword".getBytes();
+ final LockscreenCredential oldCredential = newPassword("oldPassword");
+ final LockscreenCredential newCredential = newPassword("newPassword");
initializeStorageWithCredential(
- PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
+ PRIMARY_USER_ID, oldCredential, 1234);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertTrue(mService.setLockCredential(
newCredential,
- CREDENTIAL_TYPE_PASSWORD,
- oldCredential.getBytes(),
- PASSWORD_QUALITY_ALPHABETIC,
+ oldCredential,
PRIMARY_USER_ID,
false));
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential, PRIMARY_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential.getCredential(),
+ PRIMARY_USER_ID);
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(
- CREDENTIAL_TYPE_PASSWORD, newCredential, MANAGED_PROFILE_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential.getCredential(),
+ MANAGED_PROFILE_USER_ID);
}
public void
testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
throws Exception {
- final String oldCredential = "oldPassword";
- initializeStorageWithCredential(
- PRIMARY_USER_ID, oldCredential, CREDENTIAL_TYPE_PASSWORD, 1234);
+ initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"), 1234);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertTrue(mService.setLockCredential(
- null,
- CREDENTIAL_TYPE_NONE,
- oldCredential.getBytes(),
- PASSWORD_QUALITY_UNSPECIFIED,
+ nonePassword(),
+ newPassword("oldPassword"),
PRIMARY_USER_ID,
false));
@@ -331,17 +299,13 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
}
public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException {
- final String oldCredential = "oldPassword";
-
initializeStorageWithCredential(
PRIMARY_USER_ID,
- oldCredential,
- CREDENTIAL_TYPE_PATTERN,
- PASSWORD_QUALITY_SOMETHING);
+ newPattern("123654"),
+ 1234);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
- mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, oldCredential.getBytes(),
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
+ mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID, false);
// Verify fingerprint is removed
verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any());
@@ -353,41 +317,33 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
public void testSetLockCredential_forUnifiedToSeparateChallengeProfile_sendsNewCredentials()
throws Exception {
- final String parentPassword = "parentPassword";
- final byte[] profilePassword = "profilePassword".getBytes();
- initializeStorageWithCredential(
- PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
+ final LockscreenCredential parentPassword = newPassword("parentPassword");
+ final LockscreenCredential profilePassword = newPassword("profilePassword");
+ initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertTrue(mService.setLockCredential(
profilePassword,
- CREDENTIAL_TYPE_PASSWORD,
- null,
- PASSWORD_QUALITY_ALPHABETIC,
+ nonePassword(),
MANAGED_PROFILE_USER_ID,
false));
verify(mRecoverableKeyStoreManager)
- .lockScreenSecretChanged(
- CREDENTIAL_TYPE_PASSWORD, profilePassword, MANAGED_PROFILE_USER_ID);
+ .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, profilePassword.getCredential(),
+ MANAGED_PROFILE_USER_ID);
}
public void
testSetLockCredential_forSeparateToUnifiedChallengeProfile_doesNotSendRandomCredential()
throws Exception {
- final String parentPassword = "parentPassword";
- final String profilePassword = "12345";
- initializeStorageWithCredential(
- PRIMARY_USER_ID, parentPassword, CREDENTIAL_TYPE_PASSWORD, 1234);
+ final LockscreenCredential parentPassword = newPassword("parentPassword");
+ final LockscreenCredential profilePassword = newPattern("12345");
+ initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
// Create and verify separate profile credentials.
- testCreateCredential(
- MANAGED_PROFILE_USER_ID,
- profilePassword,
- CREDENTIAL_TYPE_PATTERN,
- PASSWORD_QUALITY_SOMETHING);
+ testCreateCredential(MANAGED_PROFILE_USER_ID, profilePassword);
mService.setSeparateProfileChallengeEnabled(
- MANAGED_PROFILE_USER_ID, false, profilePassword.getBytes());
+ MANAGED_PROFILE_USER_ID, false, profilePassword);
// Called once for setting the initial separate profile credentials and not again during
// unification.
@@ -396,132 +352,121 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
}
public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception {
- final String password = "password";
- initializeStorageWithCredential(PRIMARY_USER_ID, password, CREDENTIAL_TYPE_PASSWORD, 1234);
+ final LockscreenCredential password = newPassword("password");
+ initializeStorageWithCredential(PRIMARY_USER_ID, password, 1234);
reset(mRecoverableKeyStoreManager);
- mService.verifyCredential(
- password.getBytes(), CREDENTIAL_TYPE_PASSWORD, 1, PRIMARY_USER_ID);
+ mService.verifyCredential(password, 1, PRIMARY_USER_ID);
verify(mRecoverableKeyStoreManager)
.lockScreenSecretAvailable(
- CREDENTIAL_TYPE_PASSWORD, password.getBytes(), PRIMARY_USER_ID);
+ CREDENTIAL_TYPE_PASSWORD, password.getCredential(), PRIMARY_USER_ID);
}
public void testVerifyCredential_forProfileWithSeparateChallenge_sendsCredentials()
throws Exception {
- final byte[] pattern = "12345".getBytes();
+ final LockscreenCredential pattern = newPattern("12345");
assertTrue(mService.setLockCredential(
pattern,
- CREDENTIAL_TYPE_PATTERN,
- null,
- PASSWORD_QUALITY_SOMETHING,
+ nonePassword(),
MANAGED_PROFILE_USER_ID,
false));
reset(mRecoverableKeyStoreManager);
- mService.verifyCredential(pattern, CREDENTIAL_TYPE_PATTERN, 1, MANAGED_PROFILE_USER_ID);
+ mService.verifyCredential(pattern, 1, MANAGED_PROFILE_USER_ID);
verify(mRecoverableKeyStoreManager)
.lockScreenSecretAvailable(
- CREDENTIAL_TYPE_PATTERN, pattern, MANAGED_PROFILE_USER_ID);
+ CREDENTIAL_TYPE_PATTERN, pattern.getCredential(), MANAGED_PROFILE_USER_ID);
}
public void
testVerifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth()
throws Exception {
- final String pattern = "12345";
- initializeStorageWithCredential(PRIMARY_USER_ID, pattern, CREDENTIAL_TYPE_PATTERN, 1234);
+ final LockscreenCredential pattern = newPattern("12345");
+ initializeStorageWithCredential(PRIMARY_USER_ID, pattern, 1234);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
reset(mRecoverableKeyStoreManager);
- mService.verifyCredential(pattern.getBytes(), CREDENTIAL_TYPE_PATTERN, 1, PRIMARY_USER_ID);
+ mService.verifyCredential(pattern, 1, PRIMARY_USER_ID);
// Parent sends its credentials for both the parent and profile.
verify(mRecoverableKeyStoreManager)
.lockScreenSecretAvailable(
- CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), PRIMARY_USER_ID);
+ CREDENTIAL_TYPE_PATTERN, pattern.getCredential(), PRIMARY_USER_ID);
verify(mRecoverableKeyStoreManager)
.lockScreenSecretAvailable(
- CREDENTIAL_TYPE_PATTERN, pattern.getBytes(), MANAGED_PROFILE_USER_ID);
+ CREDENTIAL_TYPE_PATTERN, pattern.getCredential(), MANAGED_PROFILE_USER_ID);
// Profile doesn't send its own random credentials.
verify(mRecoverableKeyStoreManager, never())
.lockScreenSecretAvailable(
eq(CREDENTIAL_TYPE_PASSWORD), any(), eq(MANAGED_PROFILE_USER_ID));
}
- private void testCreateCredential(int userId, String credential, int type, int quality)
+ private void testCreateCredential(int userId, LockscreenCredential credential)
throws RemoteException {
- assertTrue(mService.setLockCredential(credential.getBytes(), type, null, quality,
- userId, false));
- assertVerifyCredentials(userId, credential, type, -1);
+ assertTrue(mService.setLockCredential(credential, nonePassword(), userId, false));
+ assertVerifyCredentials(userId, credential, -1);
}
private void testCreateCredentialFailsWithoutLockScreen(
- int userId, String credential, int type, int quality) throws RemoteException {
+ int userId, LockscreenCredential credential) throws RemoteException {
mHasSecureLockScreen = false;
try {
- mService.setLockCredential(credential.getBytes(), type, null, quality,
- userId, false);
+ mService.setLockCredential(credential, null, userId, false);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
// Success - the exception was expected.
}
- assertFalse(mService.havePassword(userId));
- assertFalse(mService.havePattern(userId));
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(userId));
}
- private void testChangeCredentials(int userId, String newCredential, int newType,
- String oldCredential, int oldType, int quality) throws RemoteException {
+ private void testChangeCredentials(int userId, LockscreenCredential newCredential,
+ LockscreenCredential oldCredential) throws RemoteException {
final long sid = 1234;
- initializeStorageWithCredential(userId, oldCredential, oldType, sid);
- assertTrue(mService.setLockCredential(newCredential.getBytes(), newType,
- oldCredential.getBytes(), quality, userId, false));
- assertVerifyCredentials(userId, newCredential, newType, sid);
+ initializeStorageWithCredential(userId, oldCredential, sid);
+ assertTrue(mService.setLockCredential(newCredential, oldCredential, userId, false));
+ assertVerifyCredentials(userId, newCredential, sid);
}
- private void assertVerifyCredentials(int userId, String credential, int type, long sid)
+ private void assertVerifyCredentials(int userId, LockscreenCredential credential, long sid)
throws RemoteException{
final long challenge = 54321;
- VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
- type, challenge, userId);
+ VerifyCredentialResponse response = mService.verifyCredential(credential,
+ challenge, userId);
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
- final int incorrectType;
- if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
- assertTrue(mService.havePassword(userId));
- assertFalse(mService.havePattern(userId));
- incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
- } else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
- assertFalse(mService.havePassword(userId));
- assertTrue(mService.havePattern(userId));
- incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+ if (credential.isPassword()) {
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
+ } else if (credential.isPin()) {
+ assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(userId));
+ } else if (credential.isPattern()) {
+ assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(userId));
} else {
- assertFalse(mService.havePassword(userId));
- assertFalse(mService.havePassword(userId));
- incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(userId));
}
- // check for bad type
- assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
- credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
// check for bad credential
+ final LockscreenCredential badCredential;
+ if (!credential.isNone()) {
+ badCredential = credential.duplicate();
+ badCredential.getCredential()[0] ^= 1;
+ } else {
+ badCredential = LockscreenCredential.createPin("0");
+ }
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
- ("0" + credential).getBytes(), type, challenge, userId).getResponseCode());
+ badCredential, challenge, userId).getResponseCode());
}
- private void initializeStorageWithCredential(int userId, String credential, int type, long sid)
- throws RemoteException {
- byte[] credentialBytes = credential == null ? null : credential.getBytes();
- byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
+ private void initializeStorageWithCredential(int userId, LockscreenCredential credential,
+ long sid) throws RemoteException {
+ byte[] oldHash = new VerifyHandle(credential.getCredential(), sid).toBytes();
if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
- mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
- type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
- : PASSWORD_QUALITY_SOMETHING, userId);
+ mService.initializeSyntheticPasswordLocked(oldHash, credential, userId);
} else {
- if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ if (credential.isPassword() || credential.isPin()) {
mStorage.writeCredentialHash(CredentialHash.create(oldHash,
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
} else {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index b60111ea3333..16176c029f8c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -88,6 +88,7 @@ public class LockSettingsShellCommandTest {
@Test
public void testWrongPassword() throws Exception {
+ when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
when(mLockPatternUtils.checkCredential(
@@ -101,6 +102,7 @@ public class LockSettingsShellCommandTest {
@Test
public void testChangePin() throws Exception {
+ when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
@@ -128,6 +130,7 @@ public class LockSettingsShellCommandTest {
@Test
public void testChangePassword() throws Exception {
+ when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
@@ -155,6 +158,7 @@ public class LockSettingsShellCommandTest {
@Test
public void testChangePattern() throws Exception {
+ when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.checkCredential(
@@ -181,6 +185,7 @@ public class LockSettingsShellCommandTest {
@Test
public void testClear() throws Exception {
+ when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.checkCredential(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
index bc61c582303a..1581d9ac1811 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTestable.java
@@ -16,20 +16,51 @@
package com.android.server.locksettings;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
import android.content.Context;
import com.android.server.PersistentDataBlockManagerInternal;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
import java.io.File;
+import java.util.Arrays;
public class LockSettingsStorageTestable extends LockSettingsStorage {
public File mStorageDir;
- public PersistentDataBlockManagerInternal mPersistentDataBlock;
+ public PersistentDataBlockManagerInternal mPersistentDataBlockManager;
+ private byte[] mPersistentData;
public LockSettingsStorageTestable(Context context, File storageDir) {
super(context);
mStorageDir = storageDir;
+ mPersistentDataBlockManager = mock(PersistentDataBlockManagerInternal.class);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ byte[] handle = (byte[]) invocation.getArguments()[0];
+ if (handle != null) {
+ mPersistentData = Arrays.copyOf(handle, handle.length);
+ } else {
+ mPersistentData = null;
+ }
+ return null;
+ }
+ }).when(mPersistentDataBlockManager).setFrpCredentialHandle(any());
+ // For some reasons, simply mocking getFrpCredentialHandle() with
+ // when(mPersistentDataBlockManager.getFrpCredentialHandle()).thenReturn(mPersistentData)
+ // does not work, I had to use the long-winded way below.
+ doAnswer(new Answer<byte[]>() {
+ @Override
+ public byte[] answer(InvocationOnMock invocation) throws Throwable {
+ return mPersistentData;
+ }
+ }).when(mPersistentDataBlockManager).getFrpCredentialHandle();
}
@Override
@@ -57,8 +88,8 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
}
@Override
- public PersistentDataBlockManagerInternal getPersistentDataBlock() {
- return mPersistentDataBlock;
+ PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
+ return mPersistentDataBlockManager;
}
private File makeDirs(File baseDir, String filePath) {
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 cb5189712685..7a18431cb8e1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -240,12 +240,12 @@ public class LockSettingsStorageTests extends AndroidTestCase {
writePasswordBytes(PASSWORD_0, 10);
writePatternBytes(PATTERN_0, 20);
- assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN,
mStorage.readCredentialHash(10).type);
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
mStorage.readCredentialHash(20).type);
mStorage.clearCache();
- assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN,
mStorage.readCredentialHash(10).type);
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
mStorage.readCredentialHash(20).type);
@@ -352,20 +352,20 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testPersistentDataBlock_unavailable() {
- mStorage.mPersistentDataBlock = null;
+ mStorage.mPersistentDataBlockManager = null;
assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
}
public void testPersistentDataBlock_empty() {
- mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
+ mStorage.mPersistentDataBlockManager = mock(PersistentDataBlockManagerInternal.class);
assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
}
public void testPersistentDataBlock_withData() {
- mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
- when(mStorage.mPersistentDataBlock.getFrpCredentialHandle())
+ mStorage.mPersistentDataBlockManager = mock(PersistentDataBlockManagerInternal.class);
+ when(mStorage.mPersistentDataBlockManager.getFrpCredentialHandle())
.thenReturn(PersistentData.toBytes(PersistentData.TYPE_SP_WEAVER, SOME_USER_ID,
DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, PAYLOAD));
@@ -378,8 +378,8 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testPersistentDataBlock_exception() {
- mStorage.mPersistentDataBlock = mock(PersistentDataBlockManagerInternal.class);
- when(mStorage.mPersistentDataBlock.getFrpCredentialHandle())
+ mStorage.mPersistentDataBlockManager = mock(PersistentDataBlockManagerInternal.class);
+ when(mStorage.mPersistentDataBlockManager.getFrpCredentialHandle())
.thenThrow(new IllegalStateException("oops"));
assertSame(PersistentData.NONE, mStorage.readPersistentDataBlock());
}
@@ -453,7 +453,7 @@ public class LockSettingsStorageTests extends AndroidTestCase {
private void assertPasswordBytes(byte[] password, int userId) {
CredentialHash cred = mStorage.readCredentialHash(userId);
- assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, cred.type);
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN, cred.type);
assertArrayEquals(password, cred.hash);
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
new file mode 100644
index 000000000000..df719b6d3d21
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.locksettings;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
+import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+
+import android.app.admin.DevicePolicyManager;
+
+import com.android.internal.widget.VerifyCredentialResponse;
+import com.android.server.locksettings.LockSettingsStorage.PersistentData;
+
+
+/** Test setting a lockscreen credential and then verify it under USER_FRP */
+public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ // FRP credential can only be verified prior to provisioning
+ mSettings.setDeviceProvisioned(false);
+ }
+
+ public void testFrpCredential_setPin() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+
+ assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode());
+ }
+
+ public void testFrpCredential_setPattern() {
+ mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID, false);
+
+ assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPattern("4321"), 0, USER_FRP).getResponseCode());
+ }
+
+ public void testFrpCredential_setPassword() {
+ mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID, false);
+
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPassword("4321"), 0, USER_FRP).getResponseCode());
+ }
+
+ public void testFrpCredential_changeCredential() {
+ mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
+ mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID, false);
+
+ assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPattern("5678"), 0, USER_FRP).getResponseCode());
+ }
+
+ public void testFrpCredential_removeCredential() {
+ mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
+
+ mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID, false);
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP));
+ }
+
+ public void testFrpCredential_cannotVerifyAfterProvsioning() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+
+ mSettings.setDeviceProvisioned(true);
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode());
+ }
+
+ public void testFrpCredential_legacyPinTypePersistentData() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+ PersistentData data = mStorage.readPersistentDataBlock();
+ // Tweak the existing persistent data to make it look like one with legacy credential type
+ assertEquals(CREDENTIAL_TYPE_PIN, data.payload[3]);
+ data.payload[3] = CREDENTIAL_TYPE_PASSWORD_OR_PIN;
+ mStorage.writePersistentDataBlock(data.type, data.userId,
+ DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, data.payload);
+
+ assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode());
+
+ }
+
+ public void testFrpCredential_legacyPasswordTypePersistentData() {
+ mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
+ PersistentData data = mStorage.readPersistentDataBlock();
+ // Tweak the existing persistent data to make it look like one with legacy credential type
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, data.payload[3]);
+ data.payload[3] = CREDENTIAL_TYPE_PASSWORD_OR_PIN;
+ mStorage.writePersistentDataBlock(data.type, data.userId,
+ DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, data.payload);
+
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 42ca42aecf70..89a279c566e0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -16,11 +16,9 @@
package com.android.server.locksettings;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
@@ -38,7 +36,6 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
@@ -72,15 +69,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testPasswordBasedSyntheticPassword() throws RemoteException {
final int USER_ID = 10;
- final byte[] password = "user-password".getBytes();
- final byte[] badPassword = "bad-password".getBytes();
+ final LockscreenCredential password = newPassword("user-password");
+ final LockscreenCredential badPassword = newPassword("bad-password");
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
mGateKeeperService, mUserManager, mPasswordSlotManager);
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
null, USER_ID);
long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken,
- PASSWORD_QUALITY_ALPHABETIC, USER_ID);
+ password, authToken, USER_ID);
AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
mGateKeeperService, handle, password, USER_ID, null);
@@ -105,97 +101,90 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testPasswordMigration() throws RemoteException {
- final byte[] password = "testPasswordMigration-password".getBytes();
+ final LockscreenCredential password = newPassword("testPasswordMigration-password");
disableSyntheticPassword();
- mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false));
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
enableSyntheticPassword();
// Performs migration
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
// SP-based verification
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayNotEquals(primaryStorageKey,
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
- protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
+ protected void initializeCredentialUnderSP(LockscreenCredential password, int userId)
+ throws RemoteException {
enableSyntheticPassword();
- int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
- : PASSWORD_QUALITY_UNSPECIFIED;
- int type = password != null ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
- : LockPatternUtils.CREDENTIAL_TYPE_NONE;
- mService.setLockCredential(password, type, null, quality, userId, false);
+ mService.setLockCredential(password, nonePassword(), userId, false);
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
+ assertTrue(mService.isSyntheticPasswordBasedCredential(userId));
}
public void testSyntheticPasswordChangeCredential() throws RemoteException {
- final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes();
- final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes();
+ final LockscreenCredential password = newPassword("password");
+ final LockscreenCredential newPassword = newPassword("newpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ mService.setLockCredential(newPassword, password, PRIMARY_USER_ID, false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordVerifyCredential() throws RemoteException {
- final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes();
- final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential badPassword = newPassword("badpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
- badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ badPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
}
public void testSyntheticPasswordClearCredential() throws RemoteException {
- final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
- final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential badPassword = newPassword("newpassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
+ mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ mService.setLockCredential(badPassword, nonePassword(),
+ PRIMARY_USER_ID, false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ badPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
- final byte[] password =
- "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes();
- final byte[] badPassword =
- "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential badPassword = newPassword("new");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
- mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ mService.setLockCredential(badPassword, password, PRIMARY_USER_ID, false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ badPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
// Check the same secret was passed each time
@@ -205,41 +194,35 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
- final byte[] password =
- "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes();
- final byte[] newPassword =
- "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential newPassword = newPassword("new");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
reset(mAuthSecretService);
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
}
public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
- final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes();
+ LockscreenCredential password = newPassword("password");
initializeCredentialUnderSP(password, SECONDARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
+ password, 0, SECONDARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
public void testNoSyntheticPasswordOrCredentialDoesNotPassAuthSecret() throws RemoteException {
- // Setting null doesn't create a synthetic password
- initializeCredentialUnderSP(null, PRIMARY_USER_ID);
-
- reset(mAuthSecretService);
mService.onUnlockUser(PRIMARY_USER_ID);
flushHandlerTasks();
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
- final byte[] password = "passwordForASyntheticPassword".getBytes();
+ LockscreenCredential password = newPassword("passwordForASyntheticPassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
reset(mAuthSecretService);
@@ -249,10 +232,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
- final byte[] password = "getASyntheticPassword".getBytes();
+ LockscreenCredential password = newPassword("getASyntheticPassword");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
+ mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
reset(mAuthSecretService);
mService.onUnlockUser(PRIMARY_USER_ID);
@@ -261,15 +243,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
- final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
+ LockscreenCredential UnifiedPassword = newPassword("unified-pwd");
disableSyntheticPassword();
- mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID, false);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
- final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
+ byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
assertTrue(primarySid != 0);
assertTrue(profileSid != 0);
assertTrue(profileSid != primarySid);
@@ -277,12 +258,12 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
// do migration
enableSyntheticPassword();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ UnifiedPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
// verify
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ UnifiedPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
@@ -295,19 +276,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
- final byte[] primaryPassword =
- "testManagedProfileSeparateChallengeMigration-primary".getBytes();
- final byte[] profilePassword =
- "testManagedProfileSeparateChallengeMigration-profile".getBytes();
+ LockscreenCredential primaryPassword = newPassword("primary");
+ LockscreenCredential profilePassword = newPassword("profile");
disableSyntheticPassword();
- mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
+ mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false);
+ mService.setLockCredential(profilePassword, nonePassword(),
+ MANAGED_PROFILE_USER_ID, false);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
- final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
+ byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
assertTrue(primarySid != 0);
assertTrue(profileSid != 0);
assertTrue(profileSid != primarySid);
@@ -315,19 +293,19 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
// do migration
enableSyntheticPassword();
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ primaryPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, MANAGED_PROFILE_USER_ID).getResponseCode());
+ profilePassword, 0, MANAGED_PROFILE_USER_ID)
+ .getResponseCode());
// verify
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ primaryPassword, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, MANAGED_PROFILE_USER_ID).getResponseCode());
+ profilePassword, 0, MANAGED_PROFILE_USER_ID)
+ .getResponseCode());
assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertArrayNotEquals(primaryStorageKey,
@@ -339,101 +317,92 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testTokenBasedResetPassword() throws RemoteException {
- final byte[] password = "password".getBytes();
- final byte[] pattern = "123654".getBytes();
- final byte[] token = "some-high-entropy-secure-token".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential pattern = newPattern("123654");
+ byte[] token = "some-high-entropy-secure-token".getBytes();
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
// Disregard any reportPasswordChanged() invocations as part of credential setup.
flushHandlerTasks();
reset(mDevicePolicyManager);
- final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
- mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
- PRIMARY_USER_ID).getResponseCode();
+ mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
- mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, handle, token, PRIMARY_USER_ID);
// Verify DPM gets notified about new device lock
flushHandlerTasks();
- final PasswordMetrics metric = PasswordMetrics.computeForCredential(
- LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(pattern)));
+ final PasswordMetrics metric = PasswordMetrics.computeForCredential(pattern);
assertEquals(metric, mService.getUserPasswordMetrics(PRIMARY_USER_ID));
verify(mDevicePolicyManager).reportPasswordChanged(PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedClearPassword() throws RemoteException {
- final byte[] password = "password".getBytes();
- final byte[] pattern = "123654".getBytes();
- final byte[] token = "some-high-entropy-secure-token".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential pattern = newPattern("123654");
+ byte[] token = "some-high-entropy-secure-token".getBytes();
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
- final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, PRIMARY_USER_ID).getResponseCode();
+ mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(nonePassword(), handle, token, PRIMARY_USER_ID);
flushHandlerTasks(); // flush the unlockUser() call before changing password again
- mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, handle, token,
+ PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
- final byte[] password = "password".getBytes();
- final byte[] pattern = "123654".getBytes();
- final byte[] newPassword = "password".getBytes();
- final byte[] token = "some-high-entropy-secure-token".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential pattern = newPattern("123654");
+ LockscreenCredential newPassword = newPassword("password");
+ byte[] token = "some-high-entropy-secure-token".getBytes();
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
- final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, PRIMARY_USER_ID).getResponseCode();
+ mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
- PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
+ mService.setLockCredential(pattern, password, PRIMARY_USER_ID, false);
- mLocalService.setLockCredentialWithToken(newPassword,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(newPassword, handle, token, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()
throws RemoteException {
- final String token = "some-high-entropy-secure-token";
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -441,9 +410,15 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()
throws RemoteException {
- final String token = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ // By first setting a password and then clearing it, we enter the state where SP is
+ // initialized but the user currently has no password
+ initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID);
+ assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
+ PRIMARY_USER_ID, false));
+ assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID));
+
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -451,12 +426,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
throws RemoteException {
- final byte[] token = "some-high-entropy-secure-token".getBytes();
- final byte[] password = "password".getBytes();
+ byte[] token = "some-high-entropy-secure-token".getBytes();
+ LockscreenCredential password = newPassword("password");
// Set up pre-SP user password
disableSyntheticPassword();
- mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
+ mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false);
enableSyntheticPassword();
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
@@ -464,14 +438,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
// Activate token (password gets migrated to SP at the same time)
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify token is activated
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
public void testEscrowTokenCannotBeActivatedOnUnmanagedUser() {
- final byte[] token = "some-high-entropy-secure-token".getBytes();
+ byte[] token = "some-high-entropy-secure-token".getBytes();
when(mUserManagerInternal.isDeviceManaged()).thenReturn(false);
when(mUserManagerInternal.isUserManaged(PRIMARY_USER_ID)).thenReturn(false);
when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
@@ -483,9 +457,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
- final byte[] password = "password".getBytes();
- final byte[] pattern = "123654".getBytes();
- final byte[] token = "some-high-entropy-secure-token".getBytes();
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential pattern = newPattern("123654");
+ byte[] token = "some-high-entropy-secure-token".getBytes();
mHasSecureLockScreen = false;
enableSyntheticPassword();
@@ -493,57 +467,50 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
try {
- mLocalService.setLockCredentialWithToken(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(password, handle, token, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
// Success - the exception was expected.
}
- assertFalse(mService.havePassword(PRIMARY_USER_ID));
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
try {
- mLocalService.setLockCredentialWithToken(pattern,
- LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, handle, token, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
// Success - the exception was expected.
}
- assertFalse(mService.havePattern(PRIMARY_USER_ID));
+ assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
}
public void testGetHashFactorPrimaryUser() throws RemoteException {
- final byte[] password = "password".getBytes();
- mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
+ LockscreenCredential password = newPassword("password");
+ mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false);
+ byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
assertNotNull(hashFactor);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
- final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
+ mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
+ byte[] newHashFactor = mService.getHashFactor(nonePassword(), PRIMARY_USER_ID);
assertNotNull(newHashFactor);
// Hash factor should never change after password change/removal
assertArrayEquals(hashFactor, newHashFactor);
}
public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
- final byte[] pattern = "1236".getBytes();
- mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
+ LockscreenCredential pattern = newPattern("1236");
+ mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID, false);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
}
public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
- final byte[] primaryPassword = "primary".getBytes();
- final byte[] profilePassword = "profile".getBytes();
- mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
- assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
+ LockscreenCredential primaryPassword = newPassword("primary");
+ LockscreenCredential profilePassword = newPassword("profile");
+ mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false);
+ mService.setLockCredential(profilePassword, nonePassword(),
+ MANAGED_PROFILE_USER_ID, false);
+ assertNotNull(
+ mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
}
public void testPasswordData_serializeDeserialize() {
@@ -551,7 +518,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
data.scryptN = 11;
data.scryptR = 22;
data.scryptP = 33;
- data.passwordType = CREDENTIAL_TYPE_PASSWORD;
+ data.credentialType = CREDENTIAL_TYPE_PASSWORD;
data.salt = PAYLOAD;
data.passwordHandle = PAYLOAD2;
@@ -560,7 +527,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
assertEquals(11, deserialized.scryptN);
assertEquals(22, deserialized.scryptR);
assertEquals(33, deserialized.scryptP);
- assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
+ assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.credentialType);
assertArrayEquals(PAYLOAD, deserialized.salt);
assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
}
@@ -569,7 +536,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
// Test that we can deserialize existing PasswordData and don't inadvertently change the
// wire format.
byte[] serialized = new byte[] {
- 0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD */
+ 0, 0, 0, 2, /* CREDENTIAL_TYPE_PASSWORD_OR_PIN */
11, /* scryptN */
22, /* scryptR */
33, /* scryptP */
@@ -583,7 +550,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
assertEquals(11, deserialized.scryptN);
assertEquals(22, deserialized.scryptR);
assertEquals(33, deserialized.scryptP);
- assertEquals(CREDENTIAL_TYPE_PASSWORD, deserialized.passwordType);
+ assertEquals(CREDENTIAL_TYPE_PASSWORD_OR_PIN, deserialized.credentialType);
assertArrayEquals(PAYLOAD, deserialized.salt);
assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
}
@@ -591,11 +558,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testGsiDisablesAuthSecret() throws RemoteException {
mGsiService.setIsGsiRunning(true);
- final byte[] password = "testGsiDisablesAuthSecret-password".getBytes();
+ LockscreenCredential password = newPassword("testGsiDisablesAuthSecret-password");
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, 0, PRIMARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index a992dd126f5d..7d3ec030e7a6 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -23,6 +23,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.UI_FOR
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.google.common.truth.Truth.assertThat;
@@ -31,7 +32,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -162,21 +162,6 @@ public class KeySyncTaskTest {
}
@Test
- public void isPin_isTrueForNumericString() {
- assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes()));
- }
-
- @Test
- public void isPin_isFalseForStringContainingLetters() {
- assertFalse(KeySyncTask.isPin("398i54369548654".getBytes()));
- }
-
- @Test
- public void isPin_isFalseForStringContainingSymbols() {
- assertFalse(KeySyncTask.isPin("-3987543643".getBytes()));
- }
-
- @Test
public void hashCredentialsBySaltedSha256_returnsSameHashForSameCredentialsAndSalt() {
String credentials = "password1234";
byte[] salt = randomBytes(16);
@@ -221,19 +206,19 @@ public class KeySyncTaskTest {
@Test
public void getUiFormat_returnsPinIfPin() {
assertEquals(UI_FORMAT_PIN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes()));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PIN));
}
@Test
public void getUiFormat_returnsPasswordIfPassword() {
assertEquals(UI_FORMAT_PASSWORD,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes()));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD));
}
@Test
public void getUiFormat_returnsPatternIfPattern() {
assertEquals(UI_FORMAT_PATTERN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes()));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN));
}
@@ -683,7 +668,7 @@ public class KeySyncTaskTest {
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
- CREDENTIAL_TYPE_PASSWORD,
+ CREDENTIAL_TYPE_PIN,
/*credential=*/ pin.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
@@ -799,7 +784,7 @@ public class KeySyncTaskTest {
mRecoverySnapshotStorage,
mSnapshotListenersStorage,
TEST_USER_ID,
- /*credentialType=*/ 3,
+ /*credentialType=*/ 5, // Some invalid credential type value
"12345".getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 2836e69f79da..03367db0c3e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -18,8 +18,6 @@ package com.android.server.wm;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -63,10 +61,8 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
private ActivityMetricsLaunchObserver mLaunchObserver;
private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
- private ActivityStack mStack;
- private TaskRecord mTask;
- private ActivityRecord mActivityRecord;
- private ActivityRecord mActivityRecordTrampoline;
+ private ActivityRecord mTrampolineActivity;
+ private ActivityRecord mTopActivity;
@Before
public void setUpAMLO() {
@@ -80,15 +76,10 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
// This seems to be the easiest way to create an ActivityRecord.
- mStack = new StackBuilder(mRootActivityContainer)
- .setActivityType(ACTIVITY_TYPE_STANDARD)
- .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
- .setOnTop(true)
- .setCreateActivity(true)
+ mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
+ mTopActivity = new ActivityBuilder(mService)
+ .setTask(mTrampolineActivity.getTaskRecord())
.build();
- mTask = mStack.topTask();
- mActivityRecord = mTask.getTopActivity();
- mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
}
@After
@@ -123,8 +114,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
}
- @Test
- public void testOnIntentStarted() throws Exception {
+ private void onIntentStarted() {
Intent intent = new Intent("action 1");
mActivityMetricsLogger.notifyActivityLaunching(intent);
@@ -134,123 +124,120 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
}
@Test
- public void testOnIntentFailed() throws Exception {
- testOnIntentStarted();
-
- ActivityRecord activityRecord = null;
+ public void testOnIntentFailed() {
+ onIntentStarted();
// Bringing an intent that's already running 'to front' is not considered
// as an ACTIVITY_LAUNCHED state transition.
mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
- activityRecord);
+ null /* launchedActivity */);
verifyAsync(mLaunchObserver).onIntentFailed();
verifyNoMoreInteractions(mLaunchObserver);
}
- @Test
- public void testOnActivityLaunched() throws Exception {
- testOnIntentStarted();
+ private void onActivityLaunched() {
+ onIntentStarted();
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
- mActivityRecord);
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
+ verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
verifyNoMoreInteractions(mLaunchObserver);
}
@Test
- public void testOnActivityLaunchFinished() throws Exception {
- testOnActivityLaunched();
+ public void testOnActivityLaunchFinished() {
+ onActivityLaunched();
- mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
- SystemClock.elapsedRealtimeNanos());
+ mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+ SystemClock.elapsedRealtimeNanos());
- mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
- SystemClock.elapsedRealtimeNanos());
+ notifyWindowsDrawn(mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord), anyLong());
- verifyNoMoreInteractions(mLaunchObserver);
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ verifyNoMoreInteractions(mLaunchObserver);
}
@Test
- public void testOnActivityLaunchCancelled() throws Exception {
- testOnActivityLaunched();
+ public void testOnActivityLaunchCancelled() {
+ onActivityLaunched();
- mActivityRecord.mDrawn = true;
+ mTopActivity.mDrawn = true;
- // Cannot time already-visible activities.
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
+ // Cannot time already-visible activities.
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord));
- verifyNoMoreInteractions(mLaunchObserver);
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
+ verifyNoMoreInteractions(mLaunchObserver);
}
@Test
- public void testOnReportFullyDrawn() throws Exception {
- testOnActivityLaunched();
+ public void testOnReportFullyDrawn() {
+ onActivityLaunched();
- mActivityMetricsLogger.logAppTransitionReportedDrawn(mActivityRecord, false);
+ mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
- verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mActivityRecord), anyLong());
+ verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
verifyNoMoreInteractions(mLaunchObserver);
}
- @Test
- public void testOnActivityLaunchedTrampoline() throws Exception {
- testOnIntentStarted();
+ private void onActivityLaunchedTrampoline() {
+ onIntentStarted();
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
- mActivityRecord);
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
+ verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
// A second, distinct, activity launch is coalesced into the the current app launch sequence
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
- mActivityRecordTrampoline);
+ mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
verifyNoMoreInteractions(mLaunchObserver);
}
+ private void notifyWindowsDrawn(ActivityRecord r) {
+ mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(),
+ SystemClock.elapsedRealtimeNanos());
+ }
+
@Test
- public void testOnActivityLaunchFinishedTrampoline() throws Exception {
- testOnActivityLaunchedTrampoline();
+ public void testOnActivityLaunchFinishedTrampoline() {
+ onActivityLaunchedTrampoline();
+
+ mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+ SystemClock.elapsedRealtimeNanos());
- mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
- SystemClock.elapsedRealtimeNanos());
+ notifyWindowsDrawn(mTrampolineActivity);
- mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
- SystemClock.elapsedRealtimeNanos());
+ notifyWindowsDrawn(mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline),
- anyLong());
- verifyNoMoreInteractions(mLaunchObserver);
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity),
+ anyLong());
+ verifyNoMoreInteractions(mLaunchObserver);
}
@Test
- public void testOnActivityLaunchCancelledTrampoline() throws Exception {
- testOnActivityLaunchedTrampoline();
+ public void testOnActivityLaunchCancelledTrampoline() {
+ onActivityLaunchedTrampoline();
- mActivityRecordTrampoline.mDrawn = true;
+ mTrampolineActivity.mDrawn = true;
- // Cannot time already-visible activities.
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
- mActivityRecordTrampoline);
+ // Cannot time already-visible activities.
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline));
- verifyNoMoreInteractions(mLaunchObserver);
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+ verifyNoMoreInteractions(mLaunchObserver);
}
@Test
- public void testActivityRecordProtoIsNotTooBig() throws Exception {
+ public void testActivityRecordProtoIsNotTooBig() {
// The ActivityRecordProto must not be too big, otherwise converting it at runtime
// will become prohibitively expensive.
- assertWithMessage("mActivityRecord: %s", mActivityRecord).
- that(activityRecordToProto(mActivityRecord).length).
- isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
+ assertWithMessage("mTopActivity: %s", mTopActivity)
+ .that(activityRecordToProto(mTopActivity).length)
+ .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
- assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline).
- that(activityRecordToProto(mActivityRecordTrampoline).length).
- isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
+ assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity)
+ .that(activityRecordToProto(mTrampolineActivity).length)
+ .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 7449efda69ac..1fb6a563aa40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -60,11 +60,9 @@ public class AppChangeTransitionTests extends WindowTestsBase {
private ActivityRecord mActivity;
public void setUpOnDisplay(DisplayContent dc) {
- mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
- mTask = createTaskInStack(mStack, 0 /* userId */);
- mActivity = WindowTestUtils.createTestActivityRecord(dc);
-
- mTask.addChild(mActivity, 0);
+ mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+ mTask = mActivity.getTask();
+ mStack = mTask.mStack;
// Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
@@ -167,7 +165,7 @@ public class AppChangeTransitionTests extends WindowTestsBase {
// setup currently defaults to no snapshot.
setUpOnDisplay(mDisplayContent);
- mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(1, mDisplayContent.mChangingApps.size());
assertTrue(mActivity.isInChangeTransition());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 5b9a785663e2..2fc03c7f13d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -21,12 +21,15 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -119,7 +122,7 @@ public class TaskStackTests extends WindowTestsBase {
@Test
public void testRemoveContainer() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
assertNotNull(stack);
assertNotNull(task);
@@ -135,10 +138,10 @@ public class TaskStackTests extends WindowTestsBase {
@Test
public void testRemoveContainer_deferRemoval() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
// Stack removal is deferred if one of its child is animating.
- task.setLocalIsAnimating(true);
+ doReturn(true).when(task).isSelfAnimating();
stack.removeIfPossible();
// For the case of deferred removal the task controller will still be connected to the its
@@ -157,8 +160,7 @@ public class TaskStackTests extends WindowTestsBase {
public void testReparent() {
// Create first stack on primary display.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
- task1.mOnDisplayChangedCalled = false;
+ final Task task1 = createTaskInStack(stack1, 0 /* userId */);
// Create second display and put second stack on it.
final DisplayContent dc = createNewDisplay();
@@ -170,7 +172,7 @@ public class TaskStackTests extends WindowTestsBase {
final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
- assertTrue(task1.mOnDisplayChangedCalled);
+ verify(task1, times(1)).onDisplayChanged(any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 2ba1834ea286..4dfa26644fa9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,11 +16,16 @@
package com.android.server.wm;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import android.graphics.Point;
import android.graphics.Rect;
@@ -45,7 +50,7 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testRemoveContainer() {
final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+ final Task task = createTaskInStack(stackController1, 0 /* userId */);
final ActivityRecord activity =
WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
@@ -59,11 +64,11 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testRemoveContainer_deferRemoval() {
final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+ final Task task = createTaskInStack(stackController1, 0 /* userId */);
final ActivityRecord activity =
WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
- task.mShouldDeferRemoval = true;
+ doReturn(true).when(task).shouldDeferRemoval();
task.removeIfPossible();
// For the case of deferred removal the task will still be connected to the its app token
@@ -81,9 +86,9 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testReparent() {
final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+ final Task task = createTaskInStack(stackController1, 0 /* userId */);
final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
+ final Task task2 = createTaskInStack(stackController2, 0 /* userId */);
boolean gotException = false;
try {
@@ -104,34 +109,33 @@ public class TaskTests extends WindowTestsBase {
task.reparent(stackController2, 0, false/* moveParents */);
assertEquals(stackController2, task.getParent());
- assertEquals(0, task.positionInParent());
- assertEquals(1, task2.positionInParent());
+ assertEquals(0, task.getParent().mChildren.indexOf(task));
+ assertEquals(1, task2.getParent().mChildren.indexOf(task2));
}
@Test
public void testReparent_BetweenDisplays() {
// Create first stack on primary display.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
- task.mOnDisplayChangedCalled = false;
+ final Task task = createTaskInStack(stack1, 0 /* userId */);
assertEquals(mDisplayContent, stack1.getDisplayContent());
// Create second display and put second stack on it.
final DisplayContent dc = createNewDisplay();
final TaskStack stack2 = createTaskStackOnDisplay(dc);
- final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
+ final Task task2 = createTaskInStack(stack2, 0 /* userId */);
// Reparent and check state
task.reparent(stack2, 0, false /* moveParents */);
assertEquals(stack2, task.getParent());
- assertEquals(0, task.positionInParent());
- assertEquals(1, task2.positionInParent());
- assertTrue(task.mOnDisplayChangedCalled);
+ assertEquals(0, task.getParent().mChildren.indexOf(task));
+ assertEquals(1, task2.getParent().mChildren.indexOf(task2));
+ verify(task, times(1)).onDisplayChanged(any());
}
@Test
public void testBounds() {
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
- final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
+ final Task task = createTaskInStack(stack1, 0 /* userId */);
// Check that setting bounds also updates surface position
Rect bounds = new Rect(10, 10, 100, 200);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 5c547c224225..8cd97cb8a344 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,24 +16,24 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.IWindow;
import android.view.WindowManager;
import androidx.test.filters.FlakyTest;
@@ -57,29 +57,11 @@ import org.mockito.Mockito;
@RunWith(WindowTestRunner.class)
public class WindowFrameTests extends WindowTestsBase {
- private final IWindow mIWindow = new TestIWindow();
private final Rect mEmptyRect = new Rect();
private DisplayContent mTestDisplayContent;
- static class FrameTestWindowState extends WindowState {
- boolean mDockedResizingForTest = false;
- FrameTestWindowState(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
- WindowManager.LayoutParams attrs) {
- super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
- false /* ownerCanAddInternalSystemWindow */);
- }
-
- @Override
- boolean isDockedResizing() {
- return mDockedResizingForTest;
- }
- }
-
- TaskStack mStubStack;
-
@Before
public void setUp() throws Exception {
- mStubStack = mock(TaskStack.class);
DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
testDisplayInfo.displayCutout = null;
mTestDisplayContent = createNewDisplay(testDisplayInfo);
@@ -129,8 +111,7 @@ public class WindowFrameTests extends WindowTestsBase {
expectedRect.bottom);
}
- private void assertPolicyCrop(
- FrameTestWindowState w, int left, int top, int right, int bottom) {
+ private void assertPolicyCrop(WindowState w, int left, int top, int right, int bottom) {
Rect policyCrop = new Rect();
w.calculatePolicyCrop(policyCrop);
assertRect(policyCrop, left, top, right, bottom);
@@ -139,7 +120,7 @@ public class WindowFrameTests extends WindowTestsBase {
@Test
public void testLayoutInFullscreenTaskInsets() {
// fullscreen task doesn't use bounds for computeFrame
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final int bottomContentInset = 100;
@@ -196,7 +177,7 @@ public class WindowFrameTests extends WindowTestsBase {
@Test
public void testLayoutInFullscreenTaskNoInsets() {
// fullscreen task doesn't use bounds for computeFrame
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
// With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -278,16 +259,16 @@ public class WindowFrameTests extends WindowTestsBase {
final int logicalWidth = displayInfo.logicalWidth;
final int logicalHeight = displayInfo.logicalHeight;
- final int taskLeft = logicalWidth / 4;
- final int taskTop = logicalHeight / 4;
- final int taskRight = logicalWidth / 4 * 3;
- final int taskBottom = logicalHeight / 4 * 3;
- final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ final Rect taskBounds = new Rect(
+ logicalWidth / 4, logicalHeight / 4, logicalWidth / 4 * 3, logicalHeight / 4 * 3);
+ WindowState w = createWindow();
final Task task = w.getTask();
// Use split-screen because it is non-fullscreen, but also not floating
- task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- task.setBounds(taskBounds);
+ task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ task.mTaskRecord.setBounds(taskBounds);
+ // The bounds we are requesting might be different from what the system resolved based on
+ // other factors.
+ final Rect resolvedTaskBounds = task.getBounds();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -296,8 +277,8 @@ public class WindowFrameTests extends WindowTestsBase {
w.computeFrameLw();
// For non fullscreen tasks the containing frame is based off the
// task bounds not the parent frame.
- assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
- assertContentFrame(w, taskBounds);
+ assertEquals(resolvedTaskBounds, w.getFrameLw());
+ assertContentFrame(w, resolvedTaskBounds);
assertContentInset(w, 0, 0, 0, 0);
pf.set(0, 0, logicalWidth, logicalHeight);
@@ -307,36 +288,38 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect cf = new Rect(0, 0, cfRight, cfBottom);
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
w.computeFrameLw();
- assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
- int contentInsetRight = taskRight - cfRight;
- int contentInsetBottom = taskBottom - cfBottom;
+ assertEquals(resolvedTaskBounds, w.getFrameLw());
+ int contentInsetRight = resolvedTaskBounds.right - cfRight;
+ int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom;
assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
- assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
- taskBottom - contentInsetBottom));
+ assertContentFrame(w, new Rect(resolvedTaskBounds.left, resolvedTaskBounds.top,
+ resolvedTaskBounds.right - contentInsetRight,
+ resolvedTaskBounds.bottom - contentInsetBottom));
pf.set(0, 0, logicalWidth, logicalHeight);
// If we set displayed bounds, the insets will be computed with the main task bounds
// but the frame will be positioned according to the displayed bounds.
final int insetLeft = logicalWidth / 5;
final int insetTop = logicalHeight / 5;
- final int insetRight = insetLeft + (taskRight - taskLeft);
- final int insetBottom = insetTop + (taskBottom - taskTop);
- task.setOverrideDisplayedBounds(taskBounds);
- task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
+ final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left);
+ final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
+ task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds);
+ task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom);
windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
w.computeFrameLw();
- assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
+ assertEquals(resolvedTaskBounds, w.getFrameLw());
contentInsetRight = insetRight - cfRight;
contentInsetBottom = insetBottom - cfBottom;
assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
- assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
- taskBottom - contentInsetBottom));
+ assertContentFrame(w, new Rect(resolvedTaskBounds.left, resolvedTaskBounds.top,
+ resolvedTaskBounds.right - contentInsetRight,
+ resolvedTaskBounds.bottom - contentInsetBottom));
}
@Test
@FlakyTest(bugId = 130388666)
public void testCalculatePolicyCrop() {
- final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ final WindowState w = createWindow();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -381,7 +364,7 @@ public class WindowFrameTests extends WindowTestsBase {
// to the computed window frame.
assertPolicyCrop(w, 0, 0, logicalWidth / 2, logicalHeight / 2);
- w.mDockedResizingForTest = true;
+ doReturn(true).when(w).isDockedResizing();
// But if we are docked resizing it won't be, however we will still be
// shrunk to the decor frame and the display.
assertPolicyCrop(w, 0, 0,
@@ -402,7 +385,7 @@ public class WindowFrameTests extends WindowTestsBase {
final int taskRight = logicalWidth / 4 * 3;
final int taskBottom = logicalHeight / 4 * 3;
final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
final Task task = w.getTask();
// Use split-screen because it is non-fullscreen, but also not floating
task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -440,7 +423,7 @@ public class WindowFrameTests extends WindowTestsBase {
@FlakyTest(bugId = 130388666)
public void testDisplayCutout() {
// Regular fullscreen task and window
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -464,7 +447,7 @@ public class WindowFrameTests extends WindowTestsBase {
@FlakyTest(bugId = 130388666)
public void testDisplayCutout_tempDisplayedBounds() {
// Regular fullscreen task and window
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
final Task task = w.getTask();
task.setBounds(new Rect(0, 0, 1000, 2000));
task.setOverrideDisplayedBounds(new Rect(0, -500, 1000, 1500));
@@ -489,11 +472,12 @@ public class WindowFrameTests extends WindowTestsBase {
@Test
public void testFreeformContentInsets() {
+ removeGlobalMinSizeRestriction();
// fullscreen task doesn't use bounds for computeFrame
- WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+ WindowState w = createWindow();
final Task task = w.getTask();
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
- task.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
DisplayContent dc = mTestDisplayContent;
dc.mInputMethodTarget = w;
@@ -515,7 +499,7 @@ public class WindowFrameTests extends WindowTestsBase {
// First check that it only gets moved up enough to show window.
final Rect winRect = new Rect(200, 200, 300, 500);
- task.setBounds(winRect);
+ task.mTaskRecord.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
w.computeFrameLw();
@@ -527,7 +511,7 @@ public class WindowFrameTests extends WindowTestsBase {
// Now check that it won't get moved beyond the top and then has appropriate insets
winRect.bottom = 600;
- task.setBounds(winRect);
+ task.mTaskRecord.setBounds(winRect);
w.setBounds(winRect);
w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
w.computeFrameLw();
@@ -544,16 +528,9 @@ public class WindowFrameTests extends WindowTestsBase {
assertEquals(winRect, w.getFrameLw());
}
- private FrameTestWindowState createWindow(int width, int height) {
- final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
- attrs.width = width;
- attrs.height = height;
-
- ActivityRecord activity = createActivityRecord(mTestDisplayContent,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-
- FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, activity, attrs);
- activity.addWindow(ws);
+ private WindowState createWindow() {
+ final WindowState ws = createWindow(null, TYPE_APPLICATION, mTestDisplayContent, "WindowFrameTests");
+ spyOn(ws);
return ws;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 4fbf820e339d..51daf6567a47 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -33,16 +33,16 @@ import com.android.server.wm.ActivityTestsBase.ActivityBuilder;
* A collection of static functions that provide access to WindowManager related test functionality.
*/
class WindowTestUtils {
- private static int sNextTaskId = 0;
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
- static Task createTaskInStack(WindowManagerService service, TaskStack stack,
- int userId) {
+ static Task createTaskInStack(WindowManagerService service, TaskStack stack, int userId) {
synchronized (service.mGlobalLock) {
- final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
- new ActivityManager.TaskDescription(), null);
- stack.addTask(newTask, POSITION_TOP);
- return newTask;
+ final TaskRecord task = new ActivityTestsBase.TaskBuilder(
+ stack.mActivityStack.mStackSupervisor)
+ .setUserId(userId)
+ .setStack(stack.mActivityStack)
+ .build();
+ return task.mTask;
}
}
@@ -53,17 +53,33 @@ class WindowTestUtils {
return activity;
}
+ static ActivityRecord createTestActivityRecord(ActivityStack stack) {
+ synchronized (stack.mService.mGlobalLock) {
+ final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(
+ stack.mService)
+ .setStack(stack)
+ .setCreateTask(true)
+ .build();
+ postCreateActivitySetup(activity, stack.mTaskStack.getDisplayContent());
+ return activity;
+ }
+ }
+
static ActivityRecord createTestActivityRecord(DisplayContent dc) {
synchronized (dc.mWmService.mGlobalLock) {
final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
- activity.onDisplayChanged(dc);
- activity.setOccludesParent(true);
- activity.setHidden(false);
- activity.hiddenRequested = false;
+ postCreateActivitySetup(activity, dc);
return activity;
}
}
+ private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
+ activity.onDisplayChanged(dc);
+ activity.setOccludesParent(true);
+ activity.setHidden(false);
+ activity.hiddenRequested = false;
+ }
+
static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
return createTestWindowToken(type, dc, false /* persistOnEmpty */);
}
@@ -92,49 +108,6 @@ class WindowTestUtils {
}
}
- /* Used so we can gain access to some protected members of the {@link Task} class */
- static class TestTask extends Task {
- boolean mShouldDeferRemoval = false;
- boolean mOnDisplayChangedCalled = false;
- private boolean mIsAnimating = false;
-
- TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
- int resizeMode, boolean supportsPictureInPicture,
- TaskRecord taskRecord) {
- super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture,
- new ActivityManager.TaskDescription(), taskRecord);
- stack.addTask(this, POSITION_TOP);
- }
-
- boolean shouldDeferRemoval() {
- return mShouldDeferRemoval;
- }
-
- int positionInParent() {
- return getParent().mChildren.indexOf(this);
- }
-
- @Override
- void onDisplayChanged(DisplayContent dc) {
- super.onDisplayChanged(dc);
- mOnDisplayChangedCalled = true;
- }
-
- @Override
- boolean isSelfAnimating() {
- return mIsAnimating;
- }
-
- void setLocalIsAnimating(boolean isAnimating) {
- mIsAnimating = isAnimating;
- }
- }
-
- static TestTask createTestTask(TaskStack stack) {
- return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
- false, mock(TaskRecord.class));
- }
-
/** Used to track resize reports. */
static class TestWindowState extends WindowState {
boolean mResizeReported;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index af9c51008091..780fed9805cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -211,11 +211,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
ActivityRecord createTestActivityRecord(DisplayContent dc, int
windowingMode, int activityType) {
final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
- final Task task = createTaskInStack(stack, 0 /* userId */);
- final ActivityRecord activity =
- WindowTestUtils.createTestActivityRecord(dc);
- task.addChild(activity, 0);
- return activity;
+ return WindowTestUtils.createTestActivityRecord(stack.mActivityStack);
}
WindowState createWindow(WindowState parent, int type, String name) {
@@ -327,14 +323,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
synchronized (mWm.mGlobalLock) {
- final Configuration overrideConfig = new Configuration();
- overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
- overrideConfig.windowConfiguration.setActivityType(activityType);
- final int stackId = ++sNextStackId;
- final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
- dc.setStackOnDisplay(stackId, true, stack);
- stack.onRequestedOverrideConfigurationChanged(overrideConfig);
- return stack;
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(
+ dc.mWmService.mAtmService.mRootActivityContainer)
+ .setDisplay(dc.mActivityDisplay)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setCreateActivity(false)
+ .build();
+ return stack.mTaskStack;
}
}
@@ -386,4 +382,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
displayInfo.ownerUid = SYSTEM_UID;
return createNewDisplay(displayInfo);
}
+
+ /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+ public void removeGlobalMinSizeRestriction() {
+ mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
+ }
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3f348a4bda8c..60290e3b785d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2049,6 +2049,10 @@ public final class Call {
return "DISCONNECTING";
case STATE_SELECT_PHONE_ACCOUNT:
return "SELECT_PHONE_ACCOUNT";
+ case STATE_SIMULATED_RINGING:
+ return "SIMULATED_RINGING";
+ case STATE_AUDIO_PROCESSING:
+ return "AUDIO_PROCESSING";
default:
Log.w(Call.class, "Unknown state %d", state);
return "UNKNOWN";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 06a737041f0d..f83520f1c7a7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10237,11 +10237,13 @@ public class TelephonyManager {
/**
* Action set from carrier signalling broadcast receivers to enable/disable radio
- * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+ * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
* @param subId the subscription ID that this action applies to.
* @param enabled control enable or disable radio.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void carrierActionSetRadioEnabled(int subId, boolean enabled) {
try {
ITelephony service = getITelephony();
@@ -10256,11 +10258,13 @@ public class TelephonyManager {
/**
* Action set from carrier signalling broadcast receivers to start/stop reporting default
* network available events
- * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+ * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
* @param subId the subscription ID that this action applies to.
* @param report control start/stop reporting network status.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void carrierActionReportDefaultNetworkStatus(int subId, boolean report) {
try {
ITelephony service = getITelephony();
@@ -10274,10 +10278,12 @@ public class TelephonyManager {
/**
* Action set from carrier signalling broadcast receivers to reset all carrier actions
- * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+ * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
* @param subId the subscription ID that this action applies to.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void carrierActionResetAll(int subId) {
try {
ITelephony service = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 39e00cc50f98..f79a5c654a63 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1778,21 +1778,6 @@ interface ITelephony {
boolean isInEmergencySmsMode();
/**
- * Get a list of SMS apps on a user.
- */
- String[] getSmsApps(int userId);
-
- /**
- * Get the default SMS app on a given user.
- */
- String getDefaultSmsApp(int userId);
-
- /**
- * Set the default SMS app to a given package on a given user.
- */
- void setDefaultSmsApp(int userId, String packageName);
-
- /**
* Return the modem radio power state for slot index.
*
*/
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 0b557942c87b..62ba95dc806b 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -27,6 +28,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -34,7 +37,7 @@ import java.util.EnumMap;
import java.util.Locale;
/**
- * Describes the state of any Wifi connection that is active or
+ * Describes the state of any Wi-Fi connection that is active or
* is in the process of being set up.
*/
public class WifiInfo implements Parcelable {
@@ -96,6 +99,47 @@ public class WifiInfo implements Parcelable {
private int mRssi;
/**
+ * Wi-Fi unknown technology
+ */
+ public static final int WIFI_TECHNOLOGY_UNKNOWN = 0;
+
+ /**
+ * Wi-Fi 802.11a/b/g
+ */
+ public static final int WIFI_TECHNOLOGY_LEGACY = 1;
+
+ /**
+ * Wi-Fi 802.11n
+ */
+ public static final int WIFI_TECHNOLOGY_11N = 4;
+
+ /**
+ * Wi-Fi 802.11ac
+ */
+ public static final int WIFI_TECHNOLOGY_11AC = 5;
+
+ /**
+ * Wi-Fi 802.11ax
+ */
+ public static final int WIFI_TECHNOLOGY_11AX = 6;
+
+ /** @hide */
+ @IntDef(prefix = { "WIFI_TECHNOLOGY_" }, value = {
+ WIFI_TECHNOLOGY_UNKNOWN,
+ WIFI_TECHNOLOGY_LEGACY,
+ WIFI_TECHNOLOGY_11N,
+ WIFI_TECHNOLOGY_11AC,
+ WIFI_TECHNOLOGY_11AX
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WifiTechnology{}
+
+ /**
+ * Wi-Fi technology for the connection
+ */
+ private @WifiTechnology int mWifiTechnology;
+
+ /**
* The unit in which links speeds are expressed.
*/
public static final String LINK_SPEED_UNITS = "Mbps";
@@ -286,6 +330,7 @@ public class WifiInfo implements Parcelable {
txSuccessRate = source.txSuccessRate;
rxSuccessRate = source.rxSuccessRate;
score = source.score;
+ mWifiTechnology = source.mWifiTechnology;
}
}
@@ -374,6 +419,22 @@ public class WifiInfo implements Parcelable {
}
/**
+ * Sets the Wi-Fi technology
+ * @hide
+ */
+ public void setWifiTechnology(@WifiTechnology int wifiTechnology) {
+ mWifiTechnology = wifiTechnology;
+ }
+
+ /**
+ * Get connection Wi-Fi technology
+ * @return the connection Wi-Fi technology
+ */
+ public @WifiTechnology int getWifiTechnology() {
+ return mWifiTechnology;
+ }
+
+ /**
* Returns the current link speed in {@link #LINK_SPEED_UNITS}.
* @return the link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
* @see #LINK_SPEED_UNITS
@@ -679,6 +740,7 @@ public class WifiInfo implements Parcelable {
.append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
.append(", Supplicant state: ")
.append(mSupplicantState == null ? none : mSupplicantState)
+ .append(", Wi-Fi technology: ").append(mWifiTechnology)
.append(", RSSI: ").append(mRssi)
.append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
.append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
@@ -734,6 +796,7 @@ public class WifiInfo implements Parcelable {
dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
dest.writeString(mFqdn);
dest.writeString(mProviderFriendlyName);
+ dest.writeInt(mWifiTechnology);
}
/** Implement the Parcelable interface {@hide} */
@@ -775,6 +838,7 @@ public class WifiInfo implements Parcelable {
info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
info.mFqdn = in.readString();
info.mProviderFriendlyName = in.readString();
+ info.mWifiTechnology = in.readInt();
return info;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 0ce5d66cf4f7..ea08ea8e8333 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -38,6 +38,7 @@ public class WifiInfoTest {
private static final String TEST_PACKAGE_NAME = "com.test.example";
private static final String TEST_FQDN = "test.com";
private static final String TEST_PROVIDER_NAME = "test";
+ private static final int TEST_WIFI_TECHNOLOGY = WifiInfo.WIFI_TECHNOLOGY_11AC;
/**
* Verify parcel write/read with WifiInfo.
@@ -54,6 +55,7 @@ public class WifiInfoTest {
writeWifiInfo.setFQDN(TEST_FQDN);
writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
writeWifiInfo.setNetworkSuggestionOrSpecifierPackageName(TEST_PACKAGE_NAME);
+ writeWifiInfo.setWifiTechnology(TEST_WIFI_TECHNOLOGY);
Parcel parcel = Parcel.obtain();
writeWifiInfo.writeToParcel(parcel, 0);
@@ -72,5 +74,6 @@ public class WifiInfoTest {
assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
+ assertEquals(TEST_WIFI_TECHNOLOGY, readWifiInfo.getWifiTechnology());
}
}