summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp10
-rw-r--r--api/current.txt25
-rw-r--r--api/system-current.txt47
-rw-r--r--api/test-current.txt20
-rw-r--r--cmds/input/src/com/android/commands/input/Input.java2
-rw-r--r--cmds/statsd/Android.bp6
-rw-r--r--cmds/statsd/src/atoms.proto20
-rw-r--r--cmds/statsd/src/external/PowerStatsPuller.cpp35
-rw-r--r--cmds/statsd/src/external/SubsystemSleepStatePuller.cpp36
-rw-r--r--core/java/android/app/Activity.java37
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl6
-rw-r--r--core/java/android/app/admin/PasswordMetrics.java25
-rw-r--r--core/java/android/app/role/RoleManager.java10
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java2
-rw-r--r--core/java/android/content/pm/LauncherApps.java3
-rw-r--r--core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java36
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java9
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java11
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java28
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java5
-rw-r--r--core/java/android/database/sqlite/SQLiteGlobal.java10
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java3
-rw-r--r--core/java/android/hardware/display/AmbientDisplayConfiguration.java (renamed from core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java)58
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java17
-rw-r--r--core/java/android/net/VpnService.java3
-rw-r--r--core/java/android/net/metrics/ValidationProbeEvent.java2
-rw-r--r--core/java/android/os/FileObserver.java36
-rw-r--r--core/java/android/os/Process.java7
-rw-r--r--core/java/android/os/ZygoteProcess.java161
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java5
-rw-r--r--core/java/android/provider/DeviceConfig.java20
-rw-r--r--core/java/android/provider/Settings.java27
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java46
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--core/java/android/view/DisplayEventReceiver.java18
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java55
-rw-r--r--core/java/android/view/InsetsController.java75
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java3
-rw-r--r--core/java/android/view/ScaleGestureDetector.java2
-rw-r--r--core/java/android/view/SurfaceControl.java16
-rw-r--r--core/java/android/view/View.java6
-rw-r--r--core/java/android/view/ViewConfiguration.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java53
-rw-r--r--core/java/android/view/WindowInsets.java8
-rw-r--r--core/java/android/view/autofill/AutofillManager.java18
-rw-r--r--core/java/android/view/contentcapture/ChildContentCaptureSession.java4
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureEvent.java40
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java16
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java16
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java21
-rw-r--r--core/java/android/view/textclassifier/ActionsSuggestionsHelper.java14
-rw-r--r--core/java/android/view/textclassifier/IntentFactory.java7
-rw-r--r--core/java/android/view/textclassifier/LabeledIntent.java157
-rw-r--r--core/java/android/view/textclassifier/LegacyIntentFactory.java15
-rw-r--r--core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java6
-rw-r--r--core/java/android/view/textclassifier/TemplateIntentFactory.java17
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java111
-rw-r--r--core/java/android/widget/GridView.java4
-rw-r--r--core/java/android/widget/ListView.java6
-rw-r--r--core/java/android/widget/Magnifier.java2
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java49
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java2
-rw-r--r--core/java/com/android/internal/os/Zygote.java45
-rw-r--r--core/java/com/android/internal/os/ZygoteArguments.java15
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java94
-rw-r--r--core/java/com/android/internal/os/ZygoteServer.java214
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl12
-rw-r--r--core/java/com/android/internal/widget/LockPatternChecker.java43
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java216
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java4
-rw-r--r--core/java/com/android/internal/widget/LockSettingsInternal.java6
-rw-r--r--core/jni/AndroidRuntime.cpp18
-rw-r--r--core/jni/android_hardware_SoundTrigger.cpp15
-rw-r--r--core/jni/android_media_AudioProductStrategies.cpp22
-rw-r--r--core/jni/android_net_LocalSocketImpl.cpp174
-rw-r--r--core/jni/android_opengl_EGL14.cpp14
-rw-r--r--core/jni/android_opengl_EGL15.cpp22
-rw-r--r--core/jni/android_opengl_EGLExt.cpp1
-rw-r--r--core/jni/android_opengl_GLES10Ext.cpp2
-rw-r--r--core/jni/android_opengl_GLES20.cpp2
-rw-r--r--core/jni/android_opengl_GLES30.cpp2
-rw-r--r--core/jni/android_opengl_GLES31.cpp2
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp22
-rw-r--r--core/jni/android_view_SurfaceControl.cpp21
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp114
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp4
-rw-r--r--core/proto/android/app/settings_enums.proto49
-rw-r--r--core/res/res/drawable/ic_action_open.xml6
-rw-r--r--core/res/res/drawable/ic_qs_battery_saver.xml12
-rw-r--r--core/res/res/values/arrays.xml16
-rw-r--r--core/res/res/values/config.xml27
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/coretests/Android.bp113
-rw-r--r--core/tests/coretests/Android.mk85
-rw-r--r--core/tests/coretests/BinderProxyCountingTestApp/Android.bp25
-rw-r--r--core/tests/coretests/BinderProxyCountingTestApp/Android.mk29
-rw-r--r--core/tests/coretests/BinderProxyCountingTestService/Android.bp25
-rw-r--r--core/tests/coretests/BinderProxyCountingTestService/Android.mk29
-rw-r--r--core/tests/coretests/BstatsTestApp/Android.bp34
-rw-r--r--core/tests/coretests/BstatsTestApp/Android.mk34
-rw-r--r--core/tests/coretests/DisabledTestApp/Android.bp8
-rw-r--r--core/tests/coretests/DisabledTestApp/Android.mk13
-rw-r--r--core/tests/coretests/EnabledTestApp/Android.bp8
-rw-r--r--core/tests/coretests/EnabledTestApp/Android.mk13
-rw-r--r--core/tests/coretests/aidl/Android.bp19
-rw-r--r--core/tests/coretests/aidl/Android.mk22
-rw-r--r--core/tests/coretests/apks/Android.bp7
-rw-r--r--core/tests/coretests/apks/Android.mk7
-rw-r--r--core/tests/coretests/apks/FrameworkCoreTests_apk.mk16
-rw-r--r--core/tests/coretests/apks/install-split-base/Android.bp6
-rw-r--r--core/tests/coretests/apks/install-split-base/Android.mk10
-rw-r--r--core/tests/coretests/apks/install-split-feature-a/Android.bp11
-rw-r--r--core/tests/coretests/apks/install-split-feature-a/Android.mk14
-rw-r--r--core/tests/coretests/apks/install/Android.bp6
-rw-r--r--core/tests/coretests/apks/install/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_bad_dex/Android.bp23
-rw-r--r--core/tests/coretests/apks/install_bad_dex/Android.mk11
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/Android.bp7
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/Android.mk13
-rw-r--r--core/tests/coretests/apks/install_decl_perm/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_decl_perm/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_jni_lib/Android.bp1
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_loc_auto/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_loc_auto/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_loc_internal/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_loc_internal/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_loc_sdcard/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_loc_sdcard/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_loc_unspecified/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_loc_unspecified/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_multi_package/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_multi_package/Android.mk14
-rw-r--r--core/tests/coretests/apks/install_use_perm_good/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_use_perm_good/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_uses_feature/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_uses_feature/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_verifier_bad/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_verifier_bad/Android.mk10
-rw-r--r--core/tests/coretests/apks/install_verifier_good/Android.bp6
-rw-r--r--core/tests/coretests/apks/install_verifier_good/Android.mk10
-rw-r--r--core/tests/coretests/apks/keyset/Android.bp120
-rw-r--r--core/tests/coretests/apks/keyset/Android.mk108
-rw-r--r--core/tests/coretests/apks/locales/Android.bp6
-rw-r--r--core/tests/coretests/apks/locales/Android.mk8
-rw-r--r--core/tests/coretests/apks/version/Android.bp54
-rw-r--r--core/tests/coretests/apks/version/Android.mk36
-rw-r--r--core/tests/coretests/apks/version_nosys/Android.bp10
-rw-r--r--core/tests/coretests/apks/version_nosys/Android.mk9
-rw-r--r--core/tests/coretests/certs/Android.bp14
-rw-r--r--core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java59
-rw-r--r--core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java60
-rw-r--r--core/tests/coretests/src/android/provider/DeviceConfigTest.java85
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java23
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java59
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java149
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java18
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java29
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java64
-rw-r--r--core/tests/utillib/Android.bp22
-rw-r--r--core/tests/utillib/Android.mk29
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java3
-rw-r--r--graphics/java/android/graphics/Bitmap.java5
-rw-r--r--libs/androidfw/DisplayEventDispatcher.cpp3
-rw-r--r--libs/androidfw/include/androidfw/DisplayEventDispatcher.h2
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp2
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp1
-rw-r--r--libs/input/PointerController.cpp6
-rw-r--r--location/lib/api/current.txt2
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java9
-rw-r--r--media/apex/java/android/media/MediaConstants.java1
-rw-r--r--media/apex/java/android/media/MediaController2.java4
-rw-r--r--media/apex/java/android/media/MediaSession2.java22
-rw-r--r--media/apex/java/android/media/Session2Token.java17
-rw-r--r--media/java/android/media/AudioManager.java25
-rw-r--r--media/java/android/media/AudioSystem.java2
-rw-r--r--media/java/android/media/IAudioService.aidl3
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java19
-rw-r--r--media/java/android/media/audiopolicy/AudioProductStrategies.java22
-rw-r--r--media/jni/Android.bp35
-rw-r--r--media/jni/android_media_MediaCodec.cpp2
-rw-r--r--media/jni/android_media_MediaCodecList.cpp2
-rw-r--r--media/jni/android_media_MediaExtractor.cpp2
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp3
-rw-r--r--media/jni/android_media_MediaMuxer.cpp2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--media/jni/android_media_Streams.cpp559
-rw-r--r--media/jni/android_media_Streams.h116
-rw-r--r--media/jni/android_media_Utils.cpp533
-rw-r--r--media/jni/android_media_Utils.h90
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp2
-rw-r--r--native/android/choreographer.cpp9
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java18
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java99
-rw-r--r--packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java37
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java3
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java67
-rw-r--r--packages/SettingsLib/Android.bp2
-rw-r--r--packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml3
-rw-r--r--packages/SettingsLib/BarChartPreference/res/values/styles.xml2
-rw-r--r--packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java3
-rw-r--r--packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt404
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java1
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java6
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml26
-rw-r--r--packages/SystemUI/res/layout/bubble_expanded_view.xml5
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml8
-rw-r--r--packages/SystemUI/res/values/styles.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java23
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java53
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java18
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java18
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java124
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java30
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto48
-rw-r--r--proto/src/wifi.proto81
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java65
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java6
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java17
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java15
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java55
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java51
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java42
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/BroadcastConstants.java10
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java63
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java8
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java27
-rw-r--r--services/core/java/com/android/server/am/UserController.java6
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java16
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java19
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java92
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java36
-rw-r--r--services/core/java/com/android/server/job/controllers/StorageController.java19
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java38
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java10
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java163
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java19
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java34
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java29
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java10
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java28
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java25
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java34
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java30
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldController.java18
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java117
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java14
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java5
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java5
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java2
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java2
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java88
-rw-r--r--services/core/java/com/android/server/rollback/RollbackStore.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java3
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java8
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java14
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java22
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java33
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java1
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp245
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java19
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java (renamed from services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java)288
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java (renamed from services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java)161
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java131
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java115
-rw-r--r--services/tests/rescueparty/how_to_run.txt1
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java73
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java62
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java224
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java7
-rw-r--r--telephony/java/android/telephony/CellSignalStrength.java2
-rw-r--r--telephony/java/android/telephony/DataSpecificRegistrationStates.java23
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationState.java2
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java32
-rw-r--r--telephony/java/android/telephony/UiccCardInfo.java31
-rw-r--r--telephony/java/android/telephony/UiccSlotInfo.java44
-rw-r--r--telephony/java/android/telephony/ims/ImsStreamMediaProfile.java23
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl2
-rw-r--r--test-base/Android.bp19
-rw-r--r--test-legacy/Android.bp36
-rw-r--r--test-legacy/Android.mk25
-rw-r--r--test-mock/Android.bp16
-rw-r--r--test-runner/Android.bp2
-rw-r--r--tests/RollbackTest/Android.mk41
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java92
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java27
-rw-r--r--tests/RollbackTest/TestApp/ACrashingV2.xml1
-rw-r--r--tests/RollbackTest/TestApp/Av1.xml1
-rw-r--r--tests/RollbackTest/TestApp/Av2.xml1
-rw-r--r--tests/RollbackTest/TestApp/Bv1.xml1
-rw-r--r--tests/RollbackTest/TestApp/Bv2.xml1
-rw-r--r--tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml19
-rw-r--r--tests/RollbackTest/TestApp/res_v1/values/values.xml20
-rw-r--r--tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml19
-rw-r--r--tests/RollbackTest/TestApp/res_v2/values/values.xml20
-rw-r--r--tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java27
-rw-r--r--tools/aapt2/cmd/Compile.cpp5
-rw-r--r--tools/aapt2/io/FileSystem.cpp8
-rw-r--r--tools/apilint/apilint.py5
-rw-r--r--tools/apilint/apilint_test.py16
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java87
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java25
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java45
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java45
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java13
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pConfig.java16
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java30
-rw-r--r--wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java76
369 files changed, 7400 insertions, 3981 deletions
diff --git a/Android.bp b/Android.bp
index 385149e3229f..4b22f9e6670e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1266,10 +1266,7 @@ stubs_defaults {
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
- ":openjdk_javadoc_files",
- ":non_openjdk_javadoc_files",
- ":android_icu4j_src_files_for_docs",
- ":conscrypt_public_api_files",
+ ":core_public_api_files",
":updatable-media-srcs-without-aidls",
"test-mock/src/**/*.java",
"test-runner/src/**/*.java",
@@ -1328,10 +1325,7 @@ stubs_defaults {
srcs: [
":opt-telephony-srcs",
":opt-net-voip-srcs",
- ":openjdk_javadoc_files",
- ":non_openjdk_javadoc_files",
- ":android_icu4j_src_files_for_docs",
- ":conscrypt_public_api_files",
+ ":core_public_api_files",
":updatable-media-srcs-without-aidls",
],
srcs_lib: "framework",
diff --git a/api/current.txt b/api/current.txt
index 09674793c185..8a7b0856feef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7435,7 +7435,10 @@ package android.app.role {
method @NonNull public android.content.Intent createRequestRoleIntent(@NonNull String);
method public boolean isRoleAvailable(@NonNull String);
method public boolean isRoleHeld(@NonNull String);
+ field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
field public static final String ROLE_BROWSER = "android.app.role.BROWSER";
+ field public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
+ field public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
field public static final String ROLE_DIALER = "android.app.role.DIALER";
field public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
field public static final String ROLE_GALLERY = "android.app.role.GALLERY";
@@ -11238,7 +11241,7 @@ package android.content.pm {
public class LauncherApps {
method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(String, android.os.UserHandle);
method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllPackageInstallerSessions();
- method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(String, android.os.UserHandle);
+ method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String, @NonNull android.os.UserHandle);
method public android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
method public java.util.List<android.os.UserHandle> getProfiles();
@@ -26032,6 +26035,7 @@ package android.media {
public static final class MediaSession2.Builder {
ctor public MediaSession2.Builder(@NonNull android.content.Context);
method @NonNull public android.media.MediaSession2 build();
+ method @NonNull public android.media.MediaSession2.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaSession2.Builder setId(@NonNull String);
method @NonNull public android.media.MediaSession2.Builder setSessionActivity(@Nullable android.app.PendingIntent);
method @NonNull public android.media.MediaSession2.Builder setSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaSession2.SessionCallback);
@@ -26394,6 +26398,7 @@ package android.media {
public final class Session2Token implements android.os.Parcelable {
ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
method public int describeContents();
+ method @Nullable public android.os.Bundle getExtras();
method @NonNull public String getPackageName();
method @Nullable public String getServiceName();
method public int getType();
@@ -29353,7 +29358,7 @@ package android.net {
method public android.os.ParcelFileDescriptor establish();
method public android.net.VpnService.Builder setBlocking(boolean);
method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent);
- method public android.net.VpnService.Builder setHttpProxy(android.net.ProxyInfo);
+ method public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);
method public android.net.VpnService.Builder setMetered(boolean);
method public android.net.VpnService.Builder setMtu(int);
method public android.net.VpnService.Builder setSession(String);
@@ -29941,13 +29946,14 @@ package android.net.wifi {
method public String getMacAddress();
method public int getNetworkId();
method public int getRssi();
- method public int getRxLinkSpeedMbps();
+ method @IntRange(from=0xffffffff) public int getRxLinkSpeedMbps();
method public String getSSID();
method public android.net.wifi.SupplicantState getSupplicantState();
- method public int getTxLinkSpeedMbps();
+ method @IntRange(from=0xffffffff) public int getTxLinkSpeedMbps();
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
}
public class WifiManager {
@@ -38896,6 +38902,7 @@ package android.provider {
field public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
field public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
field public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+ field public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
field public static final String AUTO_TIME = "auto_time";
field public static final String AUTO_TIME_ZONE = "auto_time_zone";
field public static final String BLUETOOTH_ON = "bluetooth_on";
@@ -45346,13 +45353,13 @@ package android.telephony {
}
public final class UiccCardInfo implements android.os.Parcelable {
- ctor public UiccCardInfo(boolean, int, String, String, int);
method public int describeContents();
method public int getCardId();
method public String getEid();
method public String getIccId();
method public int getSlotIndex();
method public boolean isEuicc();
+ method public boolean isRemovable();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR;
}
@@ -51201,8 +51208,8 @@ package android.view {
method public int getScaledHoverSlop();
method public int getScaledMaximumDrawingCacheSize();
method public int getScaledMaximumFlingVelocity();
- method public int getScaledMinScalingSpan();
method public int getScaledMinimumFlingVelocity();
+ method public int getScaledMinimumScalingSpan();
method public int getScaledOverflingDistance();
method public int getScaledOverscrollDistance();
method public int getScaledPagingTouchSlop();
@@ -51976,16 +51983,16 @@ package android.view {
method public boolean hasInsets();
method public boolean hasStableInsets();
method public boolean hasSystemWindowInsets();
- method @NonNull public android.view.WindowInsets inset(int, int, int, int);
+ method @NonNull public android.view.WindowInsets inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
method public boolean isConsumed();
method public boolean isRound();
method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
}
- public static class WindowInsets.Builder {
+ public static final class WindowInsets.Builder {
ctor public WindowInsets.Builder();
- ctor public WindowInsets.Builder(android.view.WindowInsets);
+ ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
method @NonNull public android.view.WindowInsets build();
method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6f314f33a764..dc418989d3eb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1111,7 +1111,6 @@ package android.app.role {
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
- field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
}
public interface RoleManagerCallback {
@@ -1173,7 +1172,7 @@ package android.app.usage {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
method public int getUsageSource();
- method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, android.app.PendingIntent);
+ method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @Nullable android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
@@ -3456,6 +3455,7 @@ package android.media {
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
method public void clearAudioServerStateCallback();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies();
method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -3599,10 +3599,10 @@ package android.media.audiopolicy {
method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
method public int getFocusDuckingBehavior();
method public int getStatus();
- method public int removeUidDeviceAffinity(int);
+ method public boolean removeUidDeviceAffinity(int);
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setRegistration(String);
- method public int setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
+ method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
method public String toLogFriendlyString();
field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
@@ -3626,6 +3626,7 @@ package android.media.audiopolicy {
}
public abstract static class AudioPolicy.AudioPolicyVolumeCallback {
+ ctor public AudioPolicy.AudioPolicyVolumeCallback();
method public void onVolumeAdjustment(int);
}
@@ -3647,6 +3648,7 @@ package android.media.audiopolicy {
method @NonNull public android.media.AudioAttributes getAudioAttributesForProductStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @Nullable public android.media.audiopolicy.AudioProductStrategy getById(int);
method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes);
+ method @Nullable public android.media.audiopolicy.AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull android.media.AudioAttributes);
method public java.util.Iterator<android.media.audiopolicy.AudioProductStrategy> iterator();
method public int size();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -4849,7 +4851,8 @@ package android.net.wifi {
ctor public WifiScanner.ScanSettings();
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
- field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean ignoreLocationSettings;
+ field public boolean hideFromAppOps;
+ field public boolean ignoreLocationSettings;
field public int maxPeriodInMs;
field public int maxScansToCache;
field public int numBssidsPerScan;
@@ -5797,6 +5800,7 @@ package android.provider {
field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_SYSTEMUI = "systemui";
}
public static interface DeviceConfig.ActivityManager {
@@ -5839,14 +5843,6 @@ package android.provider {
field public static final String NAMESPACE = "media_native";
}
- public static interface DeviceConfig.NotificationAssistant {
- field public static final String GENERATE_ACTIONS = "generate_actions";
- field public static final String GENERATE_REPLIES = "generate_replies";
- field public static final String MAX_MESSAGES_TO_EXTRACT = "max_messages_to_extract";
- field public static final String MAX_SUGGESTIONS = "max_suggestions";
- field public static final String NAMESPACE = "notification_assistant";
- }
-
public static interface DeviceConfig.OnPropertyChangedListener {
method public void onPropertyChanged(String, String, String);
}
@@ -7476,6 +7472,13 @@ package android.telephony {
field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
}
+ public final class DataSpecificRegistrationStates implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationStates> CREATOR;
+ }
+
public final class DisconnectCause {
field public static final int ALREADY_DIALING = 72; // 0x48
field public static final int ANSWERED_ELSEWHERE = 52; // 0x34
@@ -7584,6 +7587,7 @@ package android.telephony {
method public int getAccessNetworkTechnology();
method public int[] getAvailableServices();
method public android.telephony.CellIdentity getCellIdentity();
+ method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates();
method public int getDomain();
method public int getRegState();
method public int getRejectCause();
@@ -8027,7 +8031,7 @@ package android.telephony {
}
public class UiccSlotInfo implements android.os.Parcelable {
- ctor public UiccSlotInfo(boolean, boolean, String, int, int, boolean);
+ ctor @Deprecated public UiccSlotInfo(boolean, boolean, String, int, int, boolean);
method public int describeContents();
method public String getCardId();
method public int getCardStateInfo();
@@ -8035,6 +8039,7 @@ package android.telephony {
method public boolean getIsEuicc();
method public boolean getIsExtendedApduSupported();
method public int getLogicalSlotIdx();
+ method public boolean isRemovable();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3
@@ -8830,12 +8835,12 @@ package android.telephony.ims {
method public int describeContents();
method public int getAudioDirection();
method public int getAudioQuality();
- method public boolean getRttAudioSpeech();
method public int getRttMode();
method public int getVideoDirection();
method public int getVideoQuality();
+ method public boolean isReceivingRttAudio();
method public boolean isRttCall();
- method public void setRttAudioSpeech(boolean);
+ method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int AUDIO_QUALITY_AMR = 1; // 0x1
@@ -9238,7 +9243,7 @@ package android.telephony.mbms {
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -9271,7 +9276,7 @@ package android.telephony.mbms.vendor {
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
@@ -9411,11 +9416,13 @@ package android.view.contentcapture {
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6
- field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
- field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
+ field public static final int TYPE_SESSION_PAUSED = 8; // 0x8
+ field public static final int TYPE_SESSION_RESUMED = 7; // 0x7
field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
+ field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
+ field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
}
public final class ContentCaptureManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index 0cd20be4b879..1089761a3ab1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -476,7 +476,6 @@ package android.app.role {
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
- field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
}
public interface RoleManagerCallback {
@@ -685,7 +684,6 @@ package android.database.sqlite {
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static String getWALSyncMode();
- method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}
@@ -742,6 +740,13 @@ package android.hardware.display {
field public static final android.os.Parcelable.Creator<android.hardware.display.AmbientBrightnessDayStats> CREATOR;
}
+ public class AmbientDisplayConfiguration {
+ ctor public AmbientDisplayConfiguration(android.content.Context);
+ method public boolean alwaysOnAvailable();
+ method public boolean alwaysOnAvailableForUser(int);
+ method public boolean alwaysOnEnabled(int);
+ }
+
public final class BrightnessChangeEvent implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -1992,6 +1997,7 @@ package android.provider {
field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
+ field public static final String DOZE_ALWAYS_ON = "doze_always_on";
field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
field public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
@@ -2382,7 +2388,7 @@ package android.telephony.mbms {
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -2415,7 +2421,7 @@ package android.telephony.mbms.vendor {
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
@@ -2864,11 +2870,13 @@ package android.view.contentcapture {
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6
- field public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; // 0x5
- field public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4; // 0x4
+ field public static final int TYPE_SESSION_PAUSED = 8; // 0x8
+ field public static final int TYPE_SESSION_RESUMED = 7; // 0x7
field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
+ field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
+ field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
}
public final class ContentCaptureManager {
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 0c861cfd3e63..a0777459311b 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -196,7 +196,7 @@ public class Input extends BaseCommand {
int repeatCount = 0;
KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
- 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0/*flags*/,
+ 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
inputSource);
event.setDisplayId(displayId);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index f4086557870d..ca48881ca519 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -346,3 +346,9 @@ java_library {
javacflags: ["-XepDisableAllChecks"],
},
}
+
+// Filegroup for statsd config proto definition.
+filegroup {
+ name: "statsd-config-proto-def",
+ srcs: ["src/statsd_config.proto"],
+}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index de42398f8720..1dd68df36ba8 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -285,7 +285,7 @@ message Atom {
CategorySize category_size = 10028;
ProcStats proc_stats = 10029;
BatteryVoltage battery_voltage = 10030;
- NumBiometricsEnrolled num_fingerprints_enrolled = 10031;
+ NumFingerprintsEnrolled num_fingerprints_enrolled = 10031;
DiskIo disk_io = 10032;
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
@@ -302,7 +302,7 @@ message Atom {
BatteryCycleCount battery_cycle_count = 10045;
DebugElapsedClock debug_elapsed_clock = 10046;
DebugFailingElapsedClock debug_failing_elapsed_clock = 10047;
- NumBiometricsEnrolled num_faces_enrolled = 10048;
+ NumFacesEnrolled num_faces_enrolled = 10048;
RoleHolder role_holder = 10049;
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
@@ -4127,15 +4127,27 @@ message DiskIo {
*
* Pulled from StatsCompanionService, which queries <Biometric>Manager.
*/
-message NumBiometricsEnrolled {
+message NumFingerprintsEnrolled {
// The associated user. Eg: 0 for owners, 10+ for others.
// Defined in android/os/UserHandle.java
optional int32 user = 1;
// Number of fingerprints registered to that user.
- optional int32 num_enrolled = 2;
+ optional int32 num_fingerprints_enrolled = 2;
}
/**
+ * Pulls the number of faces for each user.
+ *
+ * Pulled from StatsCompanionService, which queries <Biometric>Manager.
+ */
+message NumFacesEnrolled {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // Number of faces registered to that user.
+ optional int32 num_faces_enrolled = 2;
+}
+/**
* A mapping of role holder -> role
*/
message RoleHolder {
diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp
index 71e5fa0c710d..c56f9a27086e 100644
--- a/cmds/statsd/src/external/PowerStatsPuller.cpp
+++ b/cmds/statsd/src/external/PowerStatsPuller.cpp
@@ -39,17 +39,40 @@ namespace android {
namespace os {
namespace statsd {
-sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
-std::mutex gPowerStatsHalMutex;
-bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
-std::vector<RailInfo> gRailInfo;
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
+static std::mutex gPowerStatsHalMutex;
+static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
+static std::vector<RailInfo> gRailInfo;
+
+struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<android::hidl::base::V1_0::IBase>& who) override {
+ // The HAL just died. Reset all handles to HAL services.
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+ gPowerStatsHal = nullptr;
+ }
+};
+
+static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
-bool getPowerStatsHal() {
+static bool getPowerStatsHalLocked() {
if (gPowerStatsHal == nullptr && gPowerStatsExist) {
gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
if (gPowerStatsHal == nullptr) {
ALOGW("Couldn't load power.stats HAL service");
gPowerStatsExist = false;
+ } else {
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ gPowerStatsHal = nullptr;
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ // We should still continue even though linking failed
+ }
}
}
return gPowerStatsHal != nullptr;
@@ -61,7 +84,7 @@ PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWE
bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
- if (!getPowerStatsHal()) {
+ if (!getPowerStatsHalLocked()) {
ALOGE("power.stats Hal not loaded");
return false;
}
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index d8229599635c..f6a4aeaa3f9e 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -60,41 +60,43 @@ namespace android {
namespace os {
namespace statsd {
-std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};
+static std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};
-sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
-sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
-sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
+static sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+static sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
-std::unordered_map<uint32_t, std::string> gEntityNames = {};
-std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
+static std::unordered_map<uint32_t, std::string> gEntityNames = {};
+static std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
-std::mutex gPowerHalMutex;
+static std::mutex gPowerHalMutex;
// The caller must be holding gPowerHalMutex.
-void deinitPowerStatsLocked() {
+static void deinitPowerStatsLocked() {
gPowerHalV1_0 = nullptr;
gPowerHalV1_1 = nullptr;
gPowerStatsHalV1_0 = nullptr;
}
-struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient {
+struct SubsystemSleepStatePullerDeathRecipient : virtual public hardware::hidl_death_recipient {
virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override {
+ const wp<android::hidl::base::V1_0::IBase>& who) override {
+
// The HAL just died. Reset all handles to HAL services.
std::lock_guard<std::mutex> lock(gPowerHalMutex);
deinitPowerStatsLocked();
}
};
-sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
+static sp<SubsystemSleepStatePullerDeathRecipient> gDeathRecipient =
+ new SubsystemSleepStatePullerDeathRecipient();
SubsystemSleepStatePuller::SubsystemSleepStatePuller() :
StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
}
// The caller must be holding gPowerHalMutex.
-bool checkResultLocked(const Return<void> &ret, const char* function) {
+static bool checkResultLocked(const Return<void> &ret, const char* function) {
if (!ret.isOk()) {
ALOGE("%s failed: requested HAL service not available. Description: %s",
function, ret.description().c_str());
@@ -108,7 +110,7 @@ bool checkResultLocked(const Return<void> &ret, const char* function) {
// The caller must be holding gPowerHalMutex.
// gPowerStatsHalV1_0 must not be null
-bool initializePowerStats() {
+static bool initializePowerStats() {
using android::hardware::power::stats::V1_0::Status;
// Clear out previous content if we are re-initializing
@@ -155,7 +157,7 @@ bool initializePowerStats() {
}
// The caller must be holding gPowerHalMutex.
-bool getPowerStatsHalLocked() {
+static bool getPowerStatsHalLocked() {
if(gPowerStatsHalV1_0 == nullptr) {
gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
if (gPowerStatsHalV1_0 == nullptr) {
@@ -180,7 +182,7 @@ bool getPowerStatsHalLocked() {
}
// The caller must be holding gPowerHalMutex.
-bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
+static bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
using android::hardware::power::stats::V1_0::Status;
if(!getPowerStatsHalLocked()) {
@@ -225,7 +227,7 @@ bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
}
// The caller must be holding gPowerHalMutex.
-bool getPowerHalLocked() {
+static bool getPowerHalLocked() {
if(gPowerHalV1_0 == nullptr) {
gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
if(gPowerHalV1_0 == nullptr) {
@@ -250,7 +252,7 @@ bool getPowerHalLocked() {
}
// The caller must be holding gPowerHalMutex.
-bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
+static bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
using android::hardware::power::V1_0::Status;
if(!getPowerHalLocked()) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 425f6d0055c5..68b2de425b72 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1037,11 +1037,15 @@ public class Activity extends ContextThemeWrapper
}
/** @hide */ private static final int CONTENT_CAPTURE_START = 1;
- /** @hide */ private static final int CONTENT_CAPTURE_STOP = 2;
+ /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 2;
+ /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 3;
+ /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
/** @hide */
@IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
CONTENT_CAPTURE_START,
+ CONTENT_CAPTURE_RESUME,
+ CONTENT_CAPTURE_PAUSE,
CONTENT_CAPTURE_STOP
})
@Retention(RetentionPolicy.SOURCE)
@@ -1051,6 +1055,10 @@ public class Activity extends ContextThemeWrapper
switch (type) {
case CONTENT_CAPTURE_START:
return "START";
+ case CONTENT_CAPTURE_RESUME:
+ return "RESUME";
+ case CONTENT_CAPTURE_PAUSE:
+ return "PAUSE";
case CONTENT_CAPTURE_STOP:
return "STOP";
default:
@@ -1077,10 +1085,16 @@ public class Activity extends ContextThemeWrapper
& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
flags |= ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE;
}
- cm.onActivityStarted(mToken, getComponentName(), flags);
+ cm.onActivityCreated(mToken, getComponentName(), flags);
+ break;
+ case CONTENT_CAPTURE_RESUME:
+ cm.onActivityResumed();
+ break;
+ case CONTENT_CAPTURE_PAUSE:
+ cm.onActivityPaused();
break;
case CONTENT_CAPTURE_STOP:
- cm.onActivityStopped();
+ cm.onActivityDestroyed();
break;
default:
Log.wtf(TAG, "Invalid @ContentCaptureNotificationType: " + type);
@@ -1639,6 +1653,8 @@ public class Activity extends ContextThemeWrapper
}
mCalled = true;
+
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_START);
}
/**
@@ -1682,7 +1698,6 @@ public class Activity extends ContextThemeWrapper
if (mAutoFillResetNeeded) {
getAutofillManager().onVisibleForAutofill();
}
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_START);
}
/**
@@ -1765,6 +1780,9 @@ public class Activity extends ContextThemeWrapper
}
}
}
+
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
+
mCalled = true;
}
@@ -2181,6 +2199,8 @@ public class Activity extends ContextThemeWrapper
mAutoFillIgnoreFirstResumePause = false;
}
}
+
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
mCalled = true;
}
@@ -2371,7 +2391,6 @@ public class Activity extends ContextThemeWrapper
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
}
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
mEnterAnimationComplete = false;
}
@@ -2442,6 +2461,8 @@ public class Activity extends ContextThemeWrapper
}
dispatchActivityDestroyed();
+
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
}
/**
@@ -3500,6 +3521,12 @@ public class Activity extends ContextThemeWrapper
* Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
* KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
* the event).
+ *
+ * To receive this callback, you must return true from onKeyDown for the current
+ * event stream.
+ *
+ * @see KeyEvent.Callback#onKeyLongPress()
+ * @see KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
*/
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return false;
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 497d5ba5fd93..b01cd0e411c7 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -277,12 +277,8 @@ interface IActivityTaskManager {
*
* @param showingKeyguard True if the keyguard is showing, false otherwise.
* @param showingAod True if AOD is showing, false otherwise.
- * @param secondaryDisplaysShowing The displayId's of the secondary displays on which the
- * keyguard is showing, or {@code null} if there is no such display. Only meaningful if showing
- * is {@code true}.
*/
- void setLockScreenShown(boolean showingKeyguard, boolean showingAod,
- in int[] secondaryDisplaysShowing);
+ void setLockScreenShown(boolean showingKeyguard, boolean showingAod);
Bundle getAssistContextExtras(int requestType);
boolean launchAssistIntent(in Intent intent, int requestType, in String hint, int userHandle,
in Bundle args);
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index e5df2c70eeec..a6bf5012d9e5 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -221,7 +221,10 @@ public class PasswordMetrics implements Parcelable {
}
};
- public static PasswordMetrics computeForPassword(@NonNull String password) {
+ /**
+ * Returns the {@code PasswordMetrics} for a given password
+ */
+ public static PasswordMetrics computeForPassword(@NonNull byte[] password) {
// Analyse the characters used
int letters = 0;
int upperCase = 0;
@@ -229,9 +232,9 @@ public class PasswordMetrics implements Parcelable {
int numeric = 0;
int symbols = 0;
int nonLetter = 0;
- final int length = password.length();
+ final int length = password.length;
for (int i = 0; i < length; i++) {
- switch (categoryChar(password.charAt(i))) {
+ switch (categoryChar((char) password[i])) {
case CHAR_LOWER_CASE:
letters++;
lowerCase++;
@@ -296,7 +299,7 @@ public class PasswordMetrics implements Parcelable {
return false;
}
- /*
+ /**
* Returns the maximum length of a sequential characters. A sequence is defined as
* monotonically increasing characters with a constant interval or the same character repeated.
*
@@ -310,19 +313,19 @@ public class PasswordMetrics implements Parcelable {
* maxLengthSequence(";;;;") == 4 (anything that repeats)
* maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
*
- * @param string the pass
+ * @param bytes the pass
* @return the number of sequential letters or digits
*/
- public static int maxLengthSequence(@NonNull String string) {
- if (string.length() == 0) return 0;
- char previousChar = string.charAt(0);
+ public static int maxLengthSequence(@NonNull byte[] bytes) {
+ if (bytes.length == 0) return 0;
+ char previousChar = (char) bytes[0];
@CharacterCatagory int category = categoryChar(previousChar); //current sequence category
int diff = 0; //difference between two consecutive characters
boolean hasDiff = false; //if we are currently targeting a sequence
int maxLength = 0; //maximum length of a sequence already found
int startSequence = 0; //where the current sequence started
- for (int current = 1; current < string.length(); current++) {
- char currentChar = string.charAt(current);
+ for (int current = 1; current < bytes.length; current++) {
+ char currentChar = (char) bytes[current];
@CharacterCatagory int categoryCurrent = categoryChar(currentChar);
int currentDiff = (int) currentChar - (int) previousChar;
if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
@@ -341,7 +344,7 @@ public class PasswordMetrics implements Parcelable {
}
previousChar = currentChar;
}
- maxLength = Math.max(maxLength, string.length() - startSequence);
+ maxLength = Math.max(maxLength, bytes.length - startSequence);
return maxLength;
}
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index edd3ef983945..7ec21f637e0c 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -71,10 +71,8 @@ public final class RoleManager {
/**
* The name of the assistant app role.
*
- * @hide
+ * @see android.service.voice.VoiceInteractionService
*/
- @SystemApi
- @TestApi
public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
/**
@@ -149,9 +147,6 @@ public final class RoleManager {
* place the call through a call redirection service.
*
* @see android.telecom.CallRedirectionService
- *
- * TODO: STOPSHIP: Make name of required roles public API
- * @hide
*/
public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
@@ -159,9 +154,6 @@ public final class RoleManager {
* The name of the call screening and caller id role.
*
* @see android.telecom.CallScreeningService
- *
- * TODO: STOPSHIP: Make name of required roles public API
- * @hide
*/
public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index dc5bdc673249..9c6bd927dd56 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -779,7 +779,7 @@ public final class UsageStatsManager {
android.Manifest.permission.SUSPEND_APPS,
android.Manifest.permission.OBSERVE_APP_USAGE})
public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
- long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) {
+ long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) {
try {
mService.registerAppUsageLimitObserver(observerId, observedEntities,
timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index f87ce827dbfb..bf556ba0b668 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -795,7 +795,8 @@ public class LauncherApps {
* @throws SecurityException when the caller is not the active launcher.
*/
@Nullable
- public LauncherApps.AppUsageLimit getAppUsageLimit(String packageName, UserHandle user) {
+ public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
+ @NonNull UserHandle user) {
try {
return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
} catch (RemoteException re) {
diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
index 8ea1db25a9a7..a2690728d9bf 100644
--- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
+++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
@@ -40,8 +40,7 @@ public class SQLiteCompatibilityWalFlags {
private static final String TAG = "SQLiteCompatibilityWalFlags";
private static volatile boolean sInitialized;
- private static volatile boolean sFlagsSet;
- private static volatile boolean sCompatibilityWalSupported;
+ private static volatile boolean sLegacyCompatibilityWalEnabled;
private static volatile String sWALSyncMode;
private static volatile long sTruncateSize = -1;
// This flag is used to avoid recursive initialization due to circular dependency on Settings
@@ -54,18 +53,9 @@ public class SQLiteCompatibilityWalFlags {
* @hide
*/
@VisibleForTesting
- public static boolean areFlagsSet() {
+ public static boolean isLegacyCompatibilityWalEnabled() {
initIfNeeded();
- return sFlagsSet;
- }
-
- /**
- * @hide
- */
- @VisibleForTesting
- public static boolean isCompatibilityWalSupported() {
- initIfNeeded();
- return sCompatibilityWalSupported;
+ return sLegacyCompatibilityWalEnabled;
}
/**
@@ -74,6 +64,14 @@ public class SQLiteCompatibilityWalFlags {
@VisibleForTesting
public static String getWALSyncMode() {
initIfNeeded();
+ // The configurable WAL sync mode should only ever be used if the legacy compatibility
+ // WAL is enabled. It should *not* have any effect if app developers explicitly turn on
+ // WAL for their database using setWriteAheadLoggingEnabled. Throwing an exception here
+ // adds an extra layer of checking that we never use it in the wrong place.
+ if (!sLegacyCompatibilityWalEnabled) {
+ throw new IllegalStateException("isLegacyCompatibilityWalEnabled() == false");
+ }
+
return sWALSyncMode;
}
@@ -131,13 +129,12 @@ public class SQLiteCompatibilityWalFlags {
sInitialized = true;
return;
}
- sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported",
- SQLiteGlobal.isCompatibilityWalSupported());
+ sLegacyCompatibilityWalEnabled = parser.getBoolean(
+ "legacy_compatibility_wal_enabled", false);
sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode());
sTruncateSize = parser.getInt("truncate_size", -1);
- Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported="
- + sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode);
- sFlagsSet = true;
+ Log.i(TAG, "Read compatibility WAL flags: legacy_compatibility_wal_enabled="
+ + sLegacyCompatibilityWalEnabled + ", wal_syncmode=" + sWALSyncMode);
sInitialized = true;
}
@@ -148,8 +145,7 @@ public class SQLiteCompatibilityWalFlags {
@TestApi
public static void reset() {
sInitialized = false;
- sFlagsSet = false;
- sCompatibilityWalSupported = false;
+ sLegacyCompatibilityWalEnabled = false;
sWALSyncMode = null;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 3c8e236a7893..3844794da980 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -300,12 +300,13 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
// Use compatibility WAL unless an app explicitly set journal/synchronous mode
// or DISABLE_COMPATIBILITY_WAL flag is set
- final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
- if (walEnabled || useCompatibilityWal) {
+ final boolean isCompatibilityWalEnabled =
+ mConfiguration.isLegacyCompatibilityWalEnabled();
+ if (walEnabled || isCompatibilityWalEnabled) {
setJournalMode("WAL");
if (mConfiguration.syncMode != null) {
setSyncMode(mConfiguration.syncMode);
- } else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
+ } else if (isCompatibilityWalEnabled) {
setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
} else {
setSyncMode(SQLiteGlobal.getWALSyncMode());
@@ -504,7 +505,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
& (SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING
- | SQLiteDatabase.DISABLE_COMPATIBILITY_WAL)) != 0;
+ | SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL)) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index dbc176614daf..852f8f2a4204 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -321,7 +321,7 @@ public final class SQLiteConnectionPool implements Closeable {
// We should do in-place switching when transitioning from compatibility WAL
// to rollback journal. Otherwise transient connection state will be lost
boolean onlyCompatWalChanged = (mConfiguration.openFlags ^ configuration.openFlags)
- == SQLiteDatabase.DISABLE_COMPATIBILITY_WAL;
+ == SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL;
if (!onlyCompatWalChanged && mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
@@ -1113,19 +1113,18 @@ public final class SQLiteConnectionPool implements Closeable {
if (directories != null) {
directories.add(new File(mConfiguration.path).getParent());
}
+ boolean isCompatibilityWalEnabled = mConfiguration.isLegacyCompatibilityWalEnabled();
printer.println("Connection pool for " + mConfiguration.path + ":");
printer.println(" Open: " + mIsOpen);
printer.println(" Max connections: " + mMaxConnectionPoolSize);
printer.println(" Total execution time: " + mTotalExecutionTimeCounter);
printer.println(" Configuration: openFlags=" + mConfiguration.openFlags
- + ", useCompatibilityWal=" + mConfiguration.useCompatibilityWal()
+ + ", isLegacyCompatibilityWalEnabled=" + isCompatibilityWalEnabled
+ ", journalMode=" + TextUtils.emptyIfNull(mConfiguration.journalMode)
+ ", syncMode=" + TextUtils.emptyIfNull(mConfiguration.syncMode));
- if (SQLiteCompatibilityWalFlags.areFlagsSet()) {
- printer.println(" Compatibility WAL settings: compatibility_wal_supported="
- + SQLiteCompatibilityWalFlags
- .isCompatibilityWalSupported() + ", wal_syncmode="
+ if (isCompatibilityWalEnabled) {
+ printer.println(" Compatibility WAL enabled: wal_syncmode="
+ SQLiteCompatibilityWalFlags.getWALSyncMode());
}
if (mConfiguration.isLookasideConfigSet()) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index ae456afdc252..dffbd89c33d2 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -266,12 +266,17 @@ public final class SQLiteDatabase extends SQLiteClosable {
*/
public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
+
+ // Note: The below value was only used on Android Pie.
+ // public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
+
/**
- * Open flag: Flag for {@link #openDatabase} to disable Compatibility WAL when opening database.
+ * Open flag: Flag for {@link #openDatabase} to enable the legacy Compatibility WAL when opening
+ * database.
*
* @hide
*/
- public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
+ public static final int ENABLE_LEGACY_COMPATIBILITY_WAL = 0x80000000;
/**
* Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
@@ -309,10 +314,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
mConfigurationLocked.journalMode = journalMode;
mConfigurationLocked.syncMode = syncMode;
- if (!SQLiteGlobal.isCompatibilityWalSupported() || (
- SQLiteCompatibilityWalFlags.areFlagsSet() && !SQLiteCompatibilityWalFlags
- .isCompatibilityWalSupported())) {
- mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
+ if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) {
+ mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL;
}
}
@@ -2123,15 +2126,18 @@ public final class SQLiteDatabase extends SQLiteClosable {
throwIfNotOpenLocked();
final int oldFlags = mConfigurationLocked.openFlags;
- final boolean walDisabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0;
- final boolean compatibilityWalDisabled = (oldFlags & DISABLE_COMPATIBILITY_WAL) != 0;
- if (walDisabled && compatibilityWalDisabled) {
+ final boolean walEnabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ final boolean compatibilityWalEnabled =
+ (oldFlags & ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
+ // WAL was never enabled for this database, so there's nothing left to do.
+ if (!walEnabled && !compatibilityWalEnabled) {
return;
}
+ // If an app explicitly disables WAL, it takes priority over any directive
+ // to use the legacy "compatibility WAL" mode.
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
- // If an app explicitly disables WAL, compatibility mode should be disabled too
- mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
+ mConfigurationLocked.openFlags &= ~ENABLE_LEGACY_COMPATIBILITY_WAL;
try {
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 48f10219921b..fcdaf0abafcb 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -17,6 +17,7 @@
package android.database.sqlite;
import android.annotation.UnsupportedAppUsage;
+
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -197,9 +198,9 @@ public final class SQLiteDatabaseConfiguration {
return path.equalsIgnoreCase(MEMORY_DB_PATH);
}
- boolean useCompatibilityWal() {
+ boolean isLegacyCompatibilityWalEnabled() {
return journalMode == null && syncMode == null
- && (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
+ && (openFlags & SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
}
private static String stripPathForLogs(String path) {
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index ff286fdb42df..d796003395f5 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -91,16 +91,6 @@ public final class SQLiteGlobal {
}
/**
- * Returns true if compatibility WAL mode is supported. In this mode, only
- * database journal mode is changed. Connection pool will use at most one connection.
- */
- public static boolean isCompatibilityWalSupported() {
- return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
- Resources.getSystem().getBoolean(
- com.android.internal.R.bool.db_compatibility_wal_supported));
- }
-
- /**
* Gets the journal size limit in bytes.
*/
public static int getJournalSizeLimit() {
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 0e869c8c19fd..8163c4d412a7 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -202,8 +202,9 @@ public abstract class SQLiteOpenHelper implements AutoCloseable {
}
mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
}
+
// Compatibility WAL is disabled if an app disables or enables WAL
- mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.DISABLE_COMPATIBILITY_WAL);
+ mOpenParamsBuilder.removeOpenFlags(SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL);
}
}
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index e19a32e72a98..b122f199bc6f 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -11,11 +11,12 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.internal.hardware;
+package android.hardware.display;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.Build;
import android.os.SystemProperties;
@@ -24,16 +25,25 @@ import android.text.TextUtils;
import com.android.internal.R;
+/**
+ * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display.
+ *
+ * {@hide}
+ */
+@TestApi
public class AmbientDisplayConfiguration {
private final Context mContext;
private final boolean mAlwaysOnByDefault;
+ /** {@hide} */
+ @TestApi
public AmbientDisplayConfiguration(Context context) {
mContext = context;
mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled);
}
+ /** {@hide} */
public boolean enabled(int user) {
return pulseOnNotificationEnabled(user)
|| pulseOnLongPressEnabled(user)
@@ -41,63 +51,83 @@ public class AmbientDisplayConfiguration {
|| wakeScreenGestureEnabled(user);
}
+ /** {@hide} */
public boolean pulseOnNotificationEnabled(int user) {
- return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user) && pulseOnNotificationAvailable();
+ return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user)
+ && pulseOnNotificationAvailable();
}
+ /** {@hide} */
public boolean pulseOnNotificationAvailable() {
return ambientDisplayAvailable();
}
+ /** {@hide} */
public boolean pickupGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_PICK_UP_GESTURE, user)
&& dozePickupSensorAvailable();
}
+ /** {@hide} */
public boolean dozePickupSensorAvailable() {
return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
}
+ /** {@hide} */
public boolean tapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
&& tapSensorAvailable();
}
+ /** {@hide} */
public boolean tapSensorAvailable() {
return !TextUtils.isEmpty(tapSensorType());
}
+ /** {@hide} */
public boolean doubleTapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
&& doubleTapSensorAvailable();
}
+ /** {@hide} */
public boolean doubleTapSensorAvailable() {
return !TextUtils.isEmpty(doubleTapSensorType());
}
+ /** {@hide} */
public boolean wakeScreenGestureAvailable() {
return mContext.getResources()
.getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
}
+ /** {@hide} */
public boolean wakeScreenGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, user)
&& wakeScreenGestureAvailable();
}
+ /** {@hide} */
+ public long getWakeLockScreenDebounce() {
+ return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce);
+ }
+
+ /** {@hide} */
public String doubleTapSensorType() {
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
+ /** {@hide} */
public String tapSensorType() {
return mContext.getResources().getString(R.string.config_dozeTapSensorType);
}
+ /** {@hide} */
public String longPressSensorType() {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
+ /** {@hide} */
public boolean pulseOnLongPressEnabled(int user) {
return pulseOnLongPressAvailable() && boolSettingDefaultOff(
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
@@ -107,28 +137,49 @@ public class AmbientDisplayConfiguration {
return !TextUtils.isEmpty(longPressSensorType());
}
+ /**
+ * Returns if Always-on-Display functionality is enabled on the display for a specified user.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnEnabled(int user) {
return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0)
&& alwaysOnAvailable() && !accessibilityInversionEnabled(user);
}
+ /**
+ * Returns if Always-on-Display functionality is available on the display.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnAvailable() {
return (alwaysOnDisplayDebuggingEnabled() || alwaysOnDisplayAvailable())
&& ambientDisplayAvailable();
}
+ /**
+ * Returns if Always-on-Display functionality is available on the display for a specified user.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnAvailableForUser(int user) {
return alwaysOnAvailable() && !accessibilityInversionEnabled(user);
}
+ /** {@hide} */
public String ambientDisplayComponent() {
return mContext.getResources().getString(R.string.config_dozeComponent);
}
+ /** {@hide} */
public boolean accessibilityInversionEnabled(int user) {
return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user);
}
+ /** {@hide} */
public boolean ambientDisplayAvailable() {
return !TextUtils.isEmpty(ambientDisplayComponent());
}
@@ -141,7 +192,6 @@ public class AmbientDisplayConfiguration {
return SystemProperties.getBoolean("debug.doze.aod", false) && Build.IS_DEBUGGABLE;
}
-
private boolean boolSettingDefaultOn(String name, int user) {
return boolSetting(name, user, 1);
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 90dccb5b82d5..45860b3858ce 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -23,8 +23,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.RoSystemProperties;
-import com.android.org.conscrypt.Conscrypt;
-import com.android.org.conscrypt.OpenSSLContextImpl;
+import com.android.org.conscrypt.ClientSessionContext;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.SSLClientSessionCache;
@@ -33,6 +32,8 @@ import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@@ -40,6 +41,7 @@ import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
@@ -251,11 +253,12 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
private SSLSocketFactory makeSocketFactory(
KeyManager[] keyManagers, TrustManager[] trustManagers) {
try {
- OpenSSLContextImpl sslContext = (OpenSSLContextImpl) Conscrypt.newPreferredSSLContextSpi();
- sslContext.engineInit(keyManagers, trustManagers, null);
- sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
- return sslContext.engineGetSocketFactory();
- } catch (KeyManagementException e) {
+ SSLContext sslContext = SSLContext.getInstance("TLS", "AndroidOpenSSL");
+ sslContext.init(keyManagers, trustManagers, null);
+ ((ClientSessionContext) sslContext.getClientSessionContext())
+ .setPersistentCache(mSessionCache);
+ return sslContext.getSocketFactory();
+ } catch (KeyManagementException | NoSuchAlgorithmException | NoSuchProviderException e) {
Log.wtf(TAG, e);
return (SSLSocketFactory) SSLSocketFactory.getDefault(); // Fallback
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 784f23311103..ebb1ae4bb795 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -19,6 +19,7 @@ package android.net;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -512,7 +513,7 @@ public class VpnService extends Service {
* Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
* and it is possible that some apps will ignore it.
*/
- public Builder setHttpProxy(ProxyInfo proxyInfo) {
+ public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) {
mConfig.proxyInfo = proxyInfo;
return this;
}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 42e8aa6dc248..a43dc60cec84 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -79,7 +79,7 @@ public final class ValidationProbeEvent implements IpConnectivityLog.Event {
}
/**
- * Utility to create an instance of {@link ApfProgramEvent}.
+ * Utility to create an instance of {@link ValidationProbeEvent}.
*/
public static class Builder {
private long mDurationMs;
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index da0389578e15..330bde541d7d 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -16,11 +16,14 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
@@ -45,6 +48,24 @@ import java.util.List;
* keep a reference to the FileObserver instance from some other live object.</p>
*/
public abstract class FileObserver {
+ /** @hide */
+ @IntDef(flag = true, value = {
+ ACCESS,
+ MODIFY,
+ ATTRIB,
+ CLOSE_WRITE,
+ CLOSE_NOWRITE,
+ OPEN,
+ MOVED_FROM,
+ MOVED_TO,
+ CREATE,
+ DELETE,
+ DELETE_SELF,
+ MOVE_SELF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NotifyEventType {}
+
/** Event type: Data was read from a file */
public static final int ACCESS = 0x00000001;
/** Event type: Data was written to a file */
@@ -71,6 +92,7 @@ public abstract class FileObserver {
public static final int MOVE_SELF = 0x00000800;
/** Event mask: All valid event types, combined */
+ @NotifyEventType
public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
| CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
| DELETE_SELF | MOVE_SELF;
@@ -90,7 +112,8 @@ public abstract class FileObserver {
observe(m_fd);
}
- public int[] startWatching(List<File> files, int mask, FileObserver observer) {
+ public int[] startWatching(List<File> files,
+ @NotifyEventType int mask, FileObserver observer) {
final int count = files.size();
final String[] paths = new String[count];
for (int i = 0; i < count; ++i) {
@@ -118,7 +141,7 @@ public abstract class FileObserver {
stopWatching(m_fd, descriptors);
}
- public void onEvent(int wfd, int mask, String path) {
+ public void onEvent(int wfd, @NotifyEventType int mask, String path) {
// look up our observer, fixing up the map if necessary...
FileObserver observer = null;
@@ -144,7 +167,8 @@ public abstract class FileObserver {
private native int init();
private native void observe(int fd);
- private native void startWatching(int fd, String[] paths, int mask, int[] wfds);
+ private native void startWatching(int fd, String[] paths,
+ @NotifyEventType int mask, int[] wfds);
private native void stopWatching(int fd, int[] wfds);
}
@@ -197,7 +221,7 @@ public abstract class FileObserver {
* @deprecated use {@link #FileObserver(File, int)} instead.
*/
@Deprecated
- public FileObserver(String path, int mask) {
+ public FileObserver(String path, @NotifyEventType int mask) {
this(new File(path), mask);
}
@@ -209,7 +233,7 @@ public abstract class FileObserver {
* @param file The file or directory to monitor
* @param mask The event or events (added together) to watch for
*/
- public FileObserver(@NonNull File file, int mask) {
+ public FileObserver(@NonNull File file, @NotifyEventType int mask) {
this(Arrays.asList(file), mask);
}
@@ -220,7 +244,7 @@ public abstract class FileObserver {
* @param files The files or directories to monitor
* @param mask The event or events (added together) to watch for
*/
- public FileObserver(@NonNull List<File> files, int mask) {
+ public FileObserver(@NonNull List<File> files, @NotifyEventType int mask) {
mFiles = files;
mMask = mask;
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9e97e375753c..cd43b42c8ca5 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -505,7 +505,6 @@ public class Process {
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
* @param packagesForUid null-ok all the packages with the same uid as this process.
- * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -525,13 +524,12 @@ public class Process {
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] packagesForUid,
- @Nullable String[] visibleVols,
@Nullable String sandboxId,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ true, zygoteArgs);
+ packagesForUid, sandboxId, /*useBlastulaPool=*/ true, zygoteArgs);
}
/** @hide */
@@ -547,13 +545,12 @@ public class Process {
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] packagesForUid,
- @Nullable String[] visibleVols,
@Nullable String sandboxId,
@Nullable String[] zygoteArgs) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
- packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ false, zygoteArgs);
+ packagesForUid, sandboxId, /*useBlastulaPool=*/ false, zygoteArgs);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index de378b0cd1bf..e49b65e63c77 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -27,7 +27,6 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.Zygote;
-import com.android.internal.util.Preconditions;
import java.io.BufferedWriter;
import java.io.DataInputStream;
@@ -122,8 +121,9 @@ public class ZygoteProcess {
new LocalSocketAddress(Zygote.BLASTULA_POOL_SECONDARY_SOCKET_NAME,
LocalSocketAddress.Namespace.RESERVED);
- // TODO (chriswailes): Uncomment when the blastula pool can be enabled.
-// fetchBlastulaPoolEnabledProp();
+ if (fetchBlastulaPoolEnabledProp()) {
+ informZygotesOfBlastulaPoolStatus();
+ }
}
public ZygoteProcess(LocalSocketAddress primarySocketAddress,
@@ -305,7 +305,6 @@ public class ZygoteProcess {
* @param invokeWith null-ok the command to invoke with.
* @param packageName null-ok the name of the package this process belongs to.
* @param packagesForUid null-ok all the packages with the same uid as this process.
- * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -323,23 +322,19 @@ public class ZygoteProcess {
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] packagesForUid,
- @Nullable String[] visibleVols,
@Nullable String sandboxId,
boolean useBlastulaPool,
@Nullable String[] zygoteArgs) {
- if (fetchBlastulaPoolEnabledProp()) {
- // TODO (chriswailes): Send the appropriate command to the zygotes
- Log.i(LOG_TAG, "Blastula pool enabled property set to: " + mBlastulaPoolEnabled);
-
- // This can't be enabled yet, but we do want to test this code path.
- mBlastulaPoolEnabled = false;
+ // TODO (chriswailes): Is there a better place to check this value?
+ if (fetchBlastulaPoolEnabledPropWithMinInterval()) {
+ informZygotesOfBlastulaPoolStatus();
}
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
- packageName, packagesForUid, visibleVols, sandboxId,
+ packageName, packagesForUid, sandboxId,
useBlastulaPool, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
@@ -387,7 +382,7 @@ public class ZygoteProcess {
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
@GuardedBy("mLock")
- private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
+ private Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
throws ZygoteStartFailedEx {
// Throw early if any of the arguments are malformed. This means we can
@@ -415,7 +410,7 @@ public class ZygoteProcess {
Process.ProcessStartResult result = new Process.ProcessStartResult();
// TODO (chriswailes): Move branch body into separate function.
- if (useBlastulaPool && isValidBlastulaCommand(args)) {
+ if (useBlastulaPool && mBlastulaPoolEnabled && isValidBlastulaCommand(args)) {
LocalSocket blastulaSessionSocket = null;
try {
@@ -444,7 +439,7 @@ public class ZygoteProcess {
// If there was an IOException using the blastula pool we will log the error and
// attempt to start the process through the Zygote.
Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
- + ex.toString());
+ + ex.getMessage());
} finally {
try {
blastulaSessionSocket.close();
@@ -531,7 +526,6 @@ public class ZygoteProcess {
* that has its state cloned from this zygote process.
* @param packageName null-ok the name of the package this process belongs to.
* @param packagesForUid null-ok all the packages with the same uid as this process.
- * @param visibleVols null-ok storage volumes that can be accessed by this process.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -550,7 +544,6 @@ public class ZygoteProcess {
boolean startChildZygote,
@Nullable String packageName,
@Nullable String[] packagesForUid,
- @Nullable String[] visibleVols,
@Nullable String sandboxId,
boolean useBlastulaPool,
@Nullable String[] extraArgs)
@@ -638,19 +631,6 @@ public class ZygoteProcess {
argsForZygote.add(sb.toString());
}
- if (visibleVols != null && visibleVols.length > 0) {
- final StringBuilder sb = new StringBuilder();
- sb.append("--visible-vols=");
-
- for (int i = 0; i < visibleVols.length; ++i) {
- if (i != 0) {
- sb.append(',');
- }
- sb.append(visibleVols[i]);
- }
- argsForZygote.add(sb.toString());
- }
-
if (sandboxId != null) {
argsForZygote.add("--sandbox-id=" + sandboxId);
}
@@ -665,7 +645,7 @@ public class ZygoteProcess {
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
- useBlastulaPool && mBlastulaPoolEnabled,
+ useBlastulaPool,
argsForZygote);
}
}
@@ -685,6 +665,10 @@ public class ZygoteProcess {
Boolean.parseBoolean(BLASTULA_POOL_ENABLED_DEFAULT));
}
+ if (origVal != mBlastulaPoolEnabled) {
+ Log.i(LOG_TAG, "blastulaPoolEnabled = " + mBlastulaPoolEnabled);
+ }
+
return origVal != mBlastulaPoolEnabled;
}
@@ -847,49 +831,57 @@ public class ZygoteProcess {
}
/**
- * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
- * already open. If a compatible session socket is already open that session socket is returned.
- * This function may block and may have to try connecting to multiple Zygotes to find the
- * appropriate one. Requires that mLock be held.
+ * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected.
*/
@GuardedBy("mLock")
- private ZygoteState openZygoteSocketIfNeeded(String abi)
- throws ZygoteStartFailedEx {
-
- Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
-
+ private void attemptConnectionToPrimaryZygote() throws IOException {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
- try {
- primaryZygoteState =
+ primaryZygoteState =
ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
- } catch (IOException ioe) {
- throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
- }
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
+ }
- if (primaryZygoteState.matches(abi)) {
- return primaryZygoteState;
- }
-
- // The primary zygote didn't match. Try the secondary.
+ /**
+ * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected.
+ */
+ @GuardedBy("mLock")
+ private void attemptConnectionToSecondaryZygote() throws IOException {
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
- try {
- secondaryZygoteState =
+ secondaryZygoteState =
ZygoteState.connect(mZygoteSecondarySocketAddress,
- mBlastulaPoolSecondarySocketAddress);
- } catch (IOException ioe) {
- throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
- }
+ mBlastulaPoolSecondarySocketAddress);
maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
}
+ }
+
+ /**
+ * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
+ * already open. If a compatible session socket is already open that session socket is returned.
+ * This function may block and may have to try connecting to multiple Zygotes to find the
+ * appropriate one. Requires that mLock be held.
+ */
+ @GuardedBy("mLock")
+ private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
+ try {
+ attemptConnectionToPrimaryZygote();
+
+ if (primaryZygoteState.matches(abi)) {
+ return primaryZygoteState;
+ }
+
+ // The primary zygote didn't match. Try the secondary.
+ attemptConnectionToSecondaryZygote();
- if (secondaryZygoteState.matches(abi)) {
- return secondaryZygoteState;
+ if (secondaryZygoteState.matches(abi)) {
+ return secondaryZygoteState;
+ }
+ } catch (IOException ioe) {
+ throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
@@ -1015,6 +1007,57 @@ public class ZygoteProcess {
}
/**
+ * Sends messages to the zygotes telling them to change the status of their blastula pools. If
+ * this notification fails the ZygoteProcess will fall back to the previous behavior.
+ */
+ private void informZygotesOfBlastulaPoolStatus() {
+ final String command = "1\n--blastula-pool-enabled=" + mBlastulaPoolEnabled + "\n";
+
+ synchronized (mLock) {
+ try {
+ attemptConnectionToPrimaryZygote();
+
+ primaryZygoteState.mZygoteOutputWriter.write(command);
+ primaryZygoteState.mZygoteOutputWriter.flush();
+ } catch (IOException ioe) {
+ mBlastulaPoolEnabled = !mBlastulaPoolEnabled;
+ Log.w(LOG_TAG, "Failed to inform zygotes of blastula pool status: "
+ + ioe.getMessage());
+ return;
+ }
+
+ try {
+ attemptConnectionToSecondaryZygote();
+
+ try {
+ secondaryZygoteState.mZygoteOutputWriter.write(command);
+ secondaryZygoteState.mZygoteOutputWriter.flush();
+
+ // Wait for the secondary Zygote to finish its work.
+ secondaryZygoteState.mZygoteInputStream.readInt();
+ } catch (IOException ioe) {
+ throw new IllegalStateException(
+ "Blastula pool state change cause an irrecoverable error",
+ ioe);
+ }
+ } catch (IOException ioe) {
+ // No secondary zygote present. This is expected on some devices.
+ }
+
+ // Wait for the response from the primary zygote here so the primary/secondary zygotes
+ // can work concurrently.
+ try {
+ // Wait for the primary zygote to finish its work.
+ primaryZygoteState.mZygoteInputStream.readInt();
+ } catch (IOException ioe) {
+ throw new IllegalStateException(
+ "Blastula pool state change cause an irrecoverable error",
+ ioe);
+ }
+ }
+ }
+
+ /**
* Starts a new zygote process as a child of this zygote. This is used to create
* secondary zygotes that inherit data from the zygote that this object
* communicates with. This returns a new ZygoteProcess representing a connection
@@ -1061,7 +1104,7 @@ public class ZygoteProcess {
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
true /* startChildZygote */, null /* packageName */,
- null /* packagesForUid */, null /* visibleVolumes */, null /* sandboxId */,
+ null /* packagesForUid */, null /* sandboxId */,
false /* useBlastulaPool */, extraArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 03b2c2c4c6f2..f1c313838731 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -109,11 +109,6 @@ public abstract class StorageManagerInternal {
@Nullable String sharedUserId, int userId);
/**
- * @return Labels of storage volumes that are visible to the given userId.
- */
- public abstract String[] getVisibleVolumesForUser(int userId);
-
- /**
* A listener for reset events in the StorageManagerService.
*/
public interface ResetListener {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 868a36b56bf4..ddb8758e18f4 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -100,27 +100,12 @@ public final class DeviceConfig {
public static final String NAMESPACE_NETD_NATIVE = "netd_native";
/**
- * Namespace for features related to the ExtServices Notification Assistant.
- * These features are applied immediately.
+ * Namespace for System UI related features.
*
* @hide
*/
@SystemApi
- public interface NotificationAssistant {
- String NAMESPACE = "notification_assistant";
- /**
- * Whether the Notification Assistant should generate replies for notifications.
- */
- String GENERATE_REPLIES = "generate_replies";
- /**
- * Whether the Notification Assistant should generate contextual actions for notifications.
- */
- String GENERATE_ACTIONS = "generate_actions";
-
- String MAX_MESSAGES_TO_EXTRACT = "max_messages_to_extract";
-
- String MAX_SUGGESTIONS = "max_suggestions";
- }
+ public static final String NAMESPACE_SYSTEMUI = "systemui";
/**
* Namespace for all runtime related features.
@@ -197,6 +182,7 @@ public final class DeviceConfig {
*/
@SystemApi
public interface MediaNative {
+ /** The flag namespace for media native features. */
String NAMESPACE = "media_native";
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4c4bd6c2990f..0d7e00f708a3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7483,6 +7483,7 @@ public final class Settings {
* @hide
*/
@SystemApi
+ @TestApi
public static final String DOZE_ALWAYS_ON = "doze_always_on";
private static final Validator DOZE_ALWAYS_ON_VALIDATOR = BOOLEAN_VALIDATOR;
@@ -9044,7 +9045,6 @@ public final class Settings {
* Whether applying ramping ringer on incoming phone call ringtone.
* <p>1 = apply ramping ringer
* <p>0 = do not apply ramping ringer
- * @hide
*/
public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
@@ -11417,7 +11417,7 @@ public final class Settings {
/**
* Feature flag to enable or disable the activity starts logging feature.
* Type: int (0 for false, 1 for true)
- * Default: 0
+ * Default: 1
* @hide
*/
public static final String ACTIVITY_STARTS_LOGGING_ENABLED
@@ -11947,6 +11947,7 @@ public final class Settings {
* bcast_deferral (long)
* bcast_deferral_decay_factor (float)
* bcast_deferral_floor (long)
+ * bcast_allow_bg_activity_start_timeout (long)
* </pre>
*
* @hide
@@ -14200,10 +14201,24 @@ public final class Settings {
* Configuration flags for SQLite Compatibility WAL. Encoded as a key-value list, separated
* by commas. E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
*
- * Supported keys:
- * compatibility_wal_supported (boolean)
- * wal_syncmode (String)
- * truncate_size (int)
+ * Supported keys:<br/>
+ * <li>
+ * <ul> {@code legacy_compatibility_wal_enabled} : A {code boolean} flag that determines
+ * whether or not "compatibility WAL" mode is enabled by default. This is a legacy flag
+ * and is honoured on Android Q and higher. This flag will be removed in a future release.
+ * </ul>
+ * <ul> {@code wal_syncmode} : A {@code String} representing the synchronization mode to use
+ * when WAL is enabled, either via {@code legacy_compatibility_wal_enabled} or using the
+ * obsolete {@code compatibility_wal_supported} flag.
+ * </ul>
+ * <ul> {@code truncate_size} : A {@code int} flag that specifies the truncate size of the
+ * WAL journal.
+ * </ul>
+ * <ul> {@code compatibility_wal_supported} : A {code boolean} flag that specifies whether
+ * the legacy "compatibility WAL" mode is enabled by default. This flag is obsolete and is
+ * only supported on Android Pie.
+ * </ul>
+ * </li>
*
* @hide
*/
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 792eda764320..463eae681f05 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -209,7 +209,7 @@ public abstract class AugmentedAutofillService extends Service {
} else {
// TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
- proxy.update(focusedId, focusedValue);
+ proxy.update(focusedId, focusedValue, callback);
}
// TODO(b/123101711): set cancellation signal
final CancellationSignal cancellationSignal = null;
@@ -299,13 +299,14 @@ public abstract class AugmentedAutofillService extends Service {
private final Object mLock = new Object();
private final IAugmentedAutofillManagerClient mClient;
private final int mSessionId;
- private final IFillCallback mCallback;
public final int taskId;
public final ComponentName componentName;
@GuardedBy("mLock")
private AutofillId mFocusedId;
@GuardedBy("mLock")
private AutofillValue mFocusedValue;
+ @GuardedBy("mLock")
+ private IFillCallback mCallback;
/**
* Id of the last field that cause the Autofill UI to be shown.
@@ -316,8 +317,8 @@ public abstract class AugmentedAutofillService extends Service {
private AutofillId mLastShownId;
// Objects used to log metrics
- private final long mRequestTime;
- private long mOnSuccessTime;
+ private final long mFirstRequestTime;
+ private long mFirstOnSuccessTime;
private long mUiFirstShownTime;
private long mUiFirstDestroyedTime;
@@ -338,7 +339,7 @@ public abstract class AugmentedAutofillService extends Service {
this.componentName = componentName;
this.mFocusedId = focusedId;
this.mFocusedValue = focusedValue;
- this.mRequestTime = requestTime;
+ this.mFirstRequestTime = requestTime;
// TODO(b/123099468): linkToDeath
}
@@ -400,11 +401,18 @@ public abstract class AugmentedAutofillService extends Service {
mClient.requestHideFillUi(mSessionId, mFocusedId);
}
- private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
+ private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
+ @NonNull IFillCallback callback) {
synchronized (mLock) {
// TODO(b/123099468): should we close the popupwindow if the focused id changed?
mFocusedId = focusedId;
mFocusedValue = focusedValue;
+ if (mCallback != null) {
+ // TODO(b/123101711): we need to check whether the previous request was
+ // completed or not, and if not, cancel it first.
+ Slog.d(TAG, "mCallback is updated.");
+ }
+ mCallback = callback;
}
}
@@ -426,11 +434,11 @@ public abstract class AugmentedAutofillService extends Service {
public void report(@ReportEvent int event) {
switch (event) {
case REPORT_EVENT_ON_SUCCESS:
- if (mOnSuccessTime == 0) {
- mOnSuccessTime = SystemClock.elapsedRealtime();
+ if (mFirstOnSuccessTime == 0) {
+ mFirstOnSuccessTime = SystemClock.elapsedRealtime();
if (DEBUG) {
- Slog.d(TAG, "Service responsed in "
- + TimeUtils.formatDuration(mOnSuccessTime - mRequestTime));
+ Slog.d(TAG, "Service responded in " + TimeUtils.formatDuration(
+ mFirstOnSuccessTime - mFirstRequestTime));
}
}
try {
@@ -443,8 +451,8 @@ public abstract class AugmentedAutofillService extends Service {
if (mUiFirstShownTime == 0) {
mUiFirstShownTime = SystemClock.elapsedRealtime();
if (DEBUG) {
- Slog.d(TAG, "UI shown in "
- + TimeUtils.formatDuration(mUiFirstShownTime - mRequestTime));
+ Slog.d(TAG, "UI shown in " + TimeUtils.formatDuration(
+ mUiFirstShownTime - mFirstRequestTime));
}
}
break;
@@ -452,9 +460,8 @@ public abstract class AugmentedAutofillService extends Service {
if (mUiFirstDestroyedTime == 0) {
mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
if (DEBUG) {
- Slog.d(TAG, "UI destroyed in "
- + TimeUtils.formatDuration(
- mUiFirstDestroyedTime - mRequestTime));
+ Slog.d(TAG, "UI destroyed in " + TimeUtils.formatDuration(
+ mUiFirstDestroyedTime - mFirstRequestTime));
}
}
break;
@@ -486,20 +493,20 @@ public abstract class AugmentedAutofillService extends Service {
pw.print(prefix); pw.println("smartSuggestion:");
mSmartSuggestion.dump(prefix2, pw);
}
- if (mOnSuccessTime > 0) {
- final long responseTime = mOnSuccessTime - mRequestTime;
+ if (mFirstOnSuccessTime > 0) {
+ final long responseTime = mFirstOnSuccessTime - mFirstRequestTime;
pw.print(prefix); pw.print("response time: ");
TimeUtils.formatDuration(responseTime, pw); pw.println();
}
if (mUiFirstShownTime > 0) {
- final long uiRenderingTime = mUiFirstShownTime - mRequestTime;
+ final long uiRenderingTime = mUiFirstShownTime - mFirstRequestTime;
pw.print(prefix); pw.print("UI rendering time: ");
TimeUtils.formatDuration(uiRenderingTime, pw); pw.println();
}
if (mUiFirstDestroyedTime > 0) {
- final long uiTotalTime = mUiFirstDestroyedTime - mRequestTime;
+ final long uiTotalTime = mUiFirstDestroyedTime - mFirstRequestTime;
pw.print(prefix); pw.print("UI life time: ");
TimeUtils.formatDuration(uiTotalTime, pw); pw.println();
}
@@ -510,6 +517,7 @@ public abstract class AugmentedAutofillService extends Service {
if (mFillWindow != null) {
if (DEBUG) Log.d(TAG, "destroying window");
mFillWindow.destroy();
+ mFillWindow = null;
}
}
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 1d8962886bd9..2d6cbd6cbcef 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -45,13 +45,12 @@ public class FeatureFlagUtils {
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
- DEFAULT_FLAGS.put("settings_dynamic_homepage", "true");
DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false");
DEFAULT_FLAGS.put("settings_slice_injection", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
- DEFAULT_FLAGS.put("settings_mainline_module", "false");
+ DEFAULT_FLAGS.put("settings_mainline_module", "true");
DEFAULT_FLAGS.put("settings_dynamic_android", "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 3e8002f4634d..60daddd663d5 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -156,6 +156,17 @@ public abstract class DisplayEventReceiver {
}
/**
+ * Called when a display config changed event is received.
+ *
+ * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
+ * timebase.
+ * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+ * @param configId The new config Id
+ */
+ public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ }
+
+ /**
* Schedules a single vertical sync pulse to be delivered when the next
* display frame begins.
*/
@@ -182,4 +193,11 @@ public abstract class DisplayEventReceiver {
private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
onHotplug(timestampNanos, physicalDisplayId, connected);
}
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ }
+
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index dd88e3c34d30..50ef91f90997 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -20,6 +20,7 @@ import static android.view.InsetsState.INSET_SIDE_BOTTOM;
import static android.view.InsetsState.INSET_SIDE_LEFT;
import static android.view.InsetsState.INSET_SIDE_RIGHT;
import static android.view.InsetsState.INSET_SIDE_TOP;
+import static android.view.InsetsState.toPublicType;
import android.annotation.Nullable;
import android.graphics.Insets;
@@ -33,6 +34,7 @@ import android.util.SparseSetArray;
import android.view.InsetsState.InsetSide;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetType;
+import android.view.WindowInsetsAnimationListener.InsetsAnimation;
import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
@@ -66,8 +68,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
private final InsetsController mController;
private final WindowInsetsAnimationListener.InsetsAnimation mAnimation;
+ private final Rect mFrame;
private Insets mCurrentInsets;
private Insets mPendingInsets;
+ private boolean mFinished;
+ private boolean mCancelled;
+ private int mFinishedShownTypes;
@VisibleForTesting
public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
@@ -86,6 +92,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
null /* typeSideMap */);
mShownInsets = calculateInsets(mInitialInsetsState, frame, consumers, true /* shown */,
mTypeSideMap);
+ mFrame = new Rect(frame);
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mConsumers);
// TODO: Check for controllability first and wait for IME if needed.
@@ -119,12 +126,26 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
@Override
public void changeInsets(Insets insets) {
+ if (mFinished) {
+ throw new IllegalStateException(
+ "Can't change insets on an animation that is finished.");
+ }
+ if (mCancelled) {
+ throw new IllegalStateException(
+ "Can't change insets on an animation that is cancelled.");
+ }
mPendingInsets = sanitize(insets);
mController.scheduleApplyChangeInsets();
}
@VisibleForTesting
- public void applyChangeInsets(InsetsState state) {
+ /**
+ * @return Whether the finish callback of this animation should be invoked.
+ */
+ public boolean applyChangeInsets(InsetsState state) {
+ if (mCancelled) {
+ return false;
+ }
final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
ArrayList<SurfaceParams> params = new ArrayList<>();
if (offset.left != 0) {
@@ -144,13 +165,40 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
mCurrentInsets = mPendingInsets;
+ if (mFinished) {
+ mController.notifyFinished(this, mFinishedShownTypes);
+ }
+ return mFinished;
}
@Override
public void finish(int shownTypes) {
- // TODO
+ if (mCancelled) {
+ return;
+ }
+ InsetsState state = new InsetsState(mController.getState());
+ for (int i = mConsumers.size() - 1; i >= 0; i--) {
+ InsetsSourceConsumer consumer = mConsumers.valueAt(i);
+ boolean visible = (shownTypes & toPublicType(consumer.getType())) != 0;
+ state.getSource(consumer.getType()).setVisible(visible);
+ }
+ Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
+ changeInsets(insets);
+ mFinished = true;
+ mFinishedShownTypes = shownTypes;
+ }
+
+ @VisibleForTesting
+ public void onCancelled() {
+ if (mFinished) {
+ return;
+ }
+ mCancelled = true;
+ mListener.onCancelled();
+ }
- mController.dispatchAnimationFinished(mAnimation);
+ InsetsAnimation getAnimation() {
+ return mAnimation;
}
private Insets calculateInsets(InsetsState state, Rect frame,
@@ -225,4 +273,3 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
}
}
}
-
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 258600019e71..08f2e8d87352 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -17,6 +17,8 @@
package android.view;
import static android.view.InsetsState.TYPE_IME;
+import static android.view.InsetsState.toPublicType;
+import static android.view.WindowInsets.Type.all;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -99,6 +101,7 @@ public class InsetsController implements WindowInsetsController {
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>();
+ private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
private WindowInsets mLastInsets;
private boolean mAnimCallbackScheduled;
@@ -107,7 +110,6 @@ public class InsetsController implements WindowInsetsController {
private final Rect mLastLegacyContentInsets = new Rect();
private final Rect mLastLegacyStableInsets = new Rect();
- private ObjectAnimator mAnimator;
private @AnimationDirection int mAnimationDirection;
private int mPendingTypesToShow;
@@ -122,19 +124,29 @@ public class InsetsController implements WindowInsetsController {
return;
}
+ mTmpFinishedControls.clear();
InsetsState state = new InsetsState(mState, true /* copySources */);
for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
- mAnimationControls.get(i).applyChangeInsets(state);
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if (mAnimationControls.get(i).applyChangeInsets(state)) {
+ mTmpFinishedControls.add(control);
+ }
}
+
WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode,
null /* typeSideMap */);
mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
+
+ for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
+ dispatchAnimationFinished(mTmpFinishedControls.get(i).getAnimation());
+ }
};
}
- void onFrameChanged(Rect frame) {
+ @VisibleForTesting
+ public void onFrameChanged(Rect frame) {
if (mFrame.equals(frame)) {
return;
}
@@ -279,7 +291,8 @@ public class InsetsController implements WindowInsetsController {
// nothing to animate.
return;
}
- // TODO: Check whether we already have a controller.
+ cancelExistingControllers(types);
+
final ArraySet<Integer> internalTypes = mState.toInternalType(types);
final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
@@ -321,7 +334,7 @@ public class InsetsController implements WindowInsetsController {
// Show request
switch(consumer.requestShow(fromIme)) {
case ShowResult.SHOW_IMMEDIATELY:
- typesReady |= InsetsState.toPublicType(TYPE_IME);
+ typesReady |= InsetsState.toPublicType(consumer.getType());
break;
case ShowResult.SHOW_DELAYED:
isReady = false;
@@ -365,6 +378,36 @@ public class InsetsController implements WindowInsetsController {
return typesReady;
}
+ private void cancelExistingControllers(@InsetType int types) {
+ for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if ((control.getTypes() & types) != 0) {
+ cancelAnimation(control);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public void notifyFinished(InsetsAnimationControlImpl controller, int shownTypes) {
+ mAnimationControls.remove(controller);
+ hideDirectly(controller.getTypes() & ~shownTypes);
+ showDirectly(controller.getTypes() & shownTypes);
+ }
+
+ void notifyControlRevoked(InsetsSourceConsumer consumer) {
+ for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
+ cancelAnimation(control);
+ }
+ }
+ }
+
+ private void cancelAnimation(InsetsAnimationControlImpl control) {
+ control.onCancelled();
+ mAnimationControls.remove(control);
+ }
+
private void applyLocalVisibilityOverride() {
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i);
@@ -455,8 +498,13 @@ public class InsetsController implements WindowInsetsController {
}
WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
+
+ private WindowInsetsAnimationController mController;
+ private ObjectAnimator mAnimator;
+
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
+ mController = controller;
if (show) {
showDirectly(types);
} else {
@@ -474,10 +522,6 @@ public class InsetsController implements WindowInsetsController {
: ANIMATION_DURATION_HIDE_MS);
mAnimator.setInterpolator(INTERPOLATOR);
mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- onAnimationFinish();
- }
@Override
public void onAnimationEnd(Animator animation) {
@@ -488,15 +532,15 @@ public class InsetsController implements WindowInsetsController {
}
@Override
- public void onCancelled() {}
+ public void onCancelled() {
+ mAnimator.cancel();
+ }
private void onAnimationFinish() {
mAnimationDirection = DIRECTION_NONE;
+ mController.finish(show ? types : 0);
}
};
- // TODO: Instead of clearing this here, properly wire up
- // InsetsAnimationControlImpl.finish() to remove this from mAnimationControls.
- mAnimationControls.clear();
// Show/hide animations always need to be relative to the display frame, in order that shown
// and hidden state insets are correct.
@@ -522,10 +566,7 @@ public class InsetsController implements WindowInsetsController {
*/
@VisibleForTesting
public void cancelExistingAnimation() {
- mAnimationDirection = DIRECTION_NONE;
- if (mAnimator != null) {
- mAnimator.cancel();
- }
+ cancelExistingControllers(all());
}
void dump(String prefix, PrintWriter pw) {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index eab83ce34708..1383463ef72f 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -77,6 +77,9 @@ public class InsetsSourceConsumer {
if (applyLocalVisibilityOverride()) {
mController.notifyVisibilityChanged();
}
+ if (mSourceControl == null) {
+ mController.notifyControlRevoked(this);
+ }
}
@VisibleForTesting
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index c24b8b2a5ee3..7c69cfde2b9e 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -201,7 +201,7 @@ public class ScaleGestureDetector {
mListener = listener;
final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2;
- mMinSpan = viewConfiguration.getScaledMinScalingSpan();
+ mMinSpan = viewConfiguration.getScaledMinimumScalingSpan();
mHandler = handler;
// Quick scale is enabled by default after JB_MR2
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ee91c8519ff4..ea7f31dd8507 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -158,6 +158,8 @@ public final class SurfaceControl implements Parcelable {
IBinder displayToken, long numFrames, long timestamp);
private static native int nativeGetActiveConfig(IBinder displayToken);
private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
+ private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
+ int[] allowedConfigs);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
@@ -1522,6 +1524,20 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
+ public static boolean setAllowedDisplayConfigs(IBinder displayToken, int[] allowedConfigs) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ if (allowedConfigs == null) {
+ throw new IllegalArgumentException("allowedConfigs must not be null");
+ }
+
+ return nativeSetAllowedDisplayConfigs(displayToken, allowedConfigs);
+ }
+
+ /**
+ * @hide
+ */
public static int[] getDisplayColorModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8b17ea693542..7afdc7055e42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9747,11 +9747,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return;
}
- session.internalNotifyViewHierarchyEvent(/* started= */ true);
+ session.internalNotifyViewTreeEvent(/* started= */ true);
try {
dispatchProvideContentCaptureStructure();
} finally {
- session.internalNotifyViewHierarchyEvent(/* started= */ false);
+ session.internalNotifyViewTreeEvent(/* started= */ false);
}
}
@@ -10968,7 +10968,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
- if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+ if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation);
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index c030ac2a0eb8..81e9c1372aed 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -979,7 +979,7 @@ public class ViewConfiguration {
* @throws IllegalStateException if this method is called on a ViewConfiguration that was
* instantiated using a constructor with no Context parameter.
*/
- public int getScaledMinScalingSpan() {
+ public int getScaledMinimumScalingSpan() {
if (!mConstructedWithContext) {
throw new IllegalStateException("Min scaling span cannot be determined when this "
+ "method is called on a ViewConfiguration that was instantiated using a "
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 91156281983d..ad0aaa6edff6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2808,14 +2808,10 @@ public final class ViewRootImpl implements ViewParent,
try {
MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
.getMainContentCaptureSession();
- if (mainSession == null) {
- Log.w(mTag, "no MainContentCaptureSession on AttachInfo");
- return;
- }
for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
String sessionId = mAttachInfo.mContentCaptureEvents
.keyAt(i);
- mainSession.notifyViewHierarchyEvent(sessionId, /* started = */ true);
+ mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
.valueAt(i);
for_each_event: for (int j = 0; j < events.size(); j++) {
@@ -2842,7 +2838,7 @@ public final class ViewRootImpl implements ViewParent,
Log.w(mTag, "invalid content capture event: " + event);
}
}
- mainSession.notifyViewHierarchyEvent(sessionId, /* started = */ false);
+ mainSession.notifyViewTreeEvent(sessionId, /* started= */ false);
}
mAttachInfo.mContentCaptureEvents = null;
} finally {
@@ -2980,12 +2976,12 @@ public final class ViewRootImpl implements ViewParent,
}
}
mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
+
// NOTE: there's no view visibility (appeared / disapparead) events when the windows focus
// is lost, so we don't need to to force a flush - there might be other events such as
// text changes, but these should be flushed independently.
if (hasWindowFocus) {
- performContentCaptureFlushIfNecessary(
- ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
+ handleContentCaptureFlush();
}
}
@@ -3613,11 +3609,9 @@ public final class ViewRootImpl implements ViewParent,
}
}
- private void performContentCaptureFlushIfNecessary(
- @ContentCaptureSession.FlushReason int flushReason) {
+ private void handleContentCaptureFlush() {
if (DEBUG_CONTENT_CAPTURE) {
- Log.v(mTag, "performContentCaptureFlushIfNecessary("
- + ContentCaptureSession.getFlushReasonAsString(flushReason) + ")");
+ Log.v(mTag, "handleContentCaptureFlush()");
}
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "flushContentCapture for "
@@ -3628,16 +3622,15 @@ public final class ViewRootImpl implements ViewParent,
final ContentCaptureManager ccm = mAttachInfo.mContentCaptureManager;
if (ccm == null) {
- Log.w(TAG, "flush content capture: no ContentCapture on AttachInfo");
+ Log.w(TAG, "No ContentCapture on AttachInfo");
return;
}
- ccm.flush(flushReason);
+ ccm.flush(ContentCaptureSession.FLUSH_REASON_VIEW_ROOT_ENTERED);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
-
private boolean draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (!surface.isValid()) {
@@ -5277,11 +5270,8 @@ public final class ViewRootImpl implements ViewParent,
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
- } else {
- final int source = q.mEvent.getSource();
- if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- return processPointerEvent(q);
- }
+ } else if (q.mEvent instanceof MotionEvent) {
+ return processMotionEvent(q);
}
return FORWARD;
}
@@ -5305,6 +5295,23 @@ public final class ViewRootImpl implements ViewParent,
return FORWARD;
}
+ private int processMotionEvent(QueuedInputEvent q) {
+ final MotionEvent event = (MotionEvent) q.mEvent;
+
+ if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+ return processPointerEvent(q);
+ }
+
+ // If the motion event is from an absolute position device, exit touch mode
+ final int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
+ if (event.isFromSource(InputDevice.SOURCE_CLASS_POSITION)) {
+ ensureTouchMode(false);
+ }
+ }
+ return FORWARD;
+ }
+
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
@@ -5637,6 +5644,12 @@ public final class ViewRootImpl implements ViewParent,
private int processGenericMotionEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
+ if (event.isFromSource(InputDevice.SOURCE_TOUCHPAD)) {
+ if (hasPointerCapture() && mView.dispatchCapturedPointerEvent(event)) {
+ return FINISH_HANDLED;
+ }
+ }
+
// Deliver the event to the view.
if (mView.dispatchGenericMotionEvent(event)) {
return FINISH_HANDLED;
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index c1536ae2b4ae..135a8912fc60 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -28,6 +28,7 @@ import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
@@ -700,7 +701,8 @@ public final class WindowInsets {
* @return the inset insets
*/
@NonNull
- public WindowInsets inset(int left, int top, int right, int bottom) {
+ public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
+ @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
Preconditions.checkArgumentNonnegative(left);
Preconditions.checkArgumentNonnegative(top);
Preconditions.checkArgumentNonnegative(right);
@@ -794,7 +796,7 @@ public final class WindowInsets {
/**
* Builder for WindowInsets.
*/
- public static class Builder {
+ public static final class Builder {
private final Insets[] mTypeInsetsMap;
private final Insets[] mTypeMaxInsetsMap;
@@ -821,7 +823,7 @@ public final class WindowInsets {
*
* @param insets the instance to initialize from.
*/
- public Builder(WindowInsets insets) {
+ public Builder(@NonNull WindowInsets insets) {
mTypeInsetsMap = insets.mTypeInsetsMap.clone();
mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 046c4c02253c..70fe230ce226 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -371,6 +371,24 @@ public final class AutofillManager {
public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
"smart_suggestion_supported_modes";
+ /**
+ * Sets how long (in ms) the augmented autofill service is bound while idle.
+ *
+ * <p>Use {@code 0} to keep it permanently bound.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT =
+ "augmented_service_idle_unbind_timeout";
+
+ /**
+ * Sets how long (in ms) the augmented autofill service request is killed if not replied.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
+ "augmented_service_request_timeout";
+
/** @hide */
public static final int RESULT_OK = 0;
/** @hide */
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 03eef5e07321..b3b0b72c8799 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -84,8 +84,8 @@ final class ChildContentCaptureSession extends ContentCaptureSession {
}
@Override
- public void internalNotifyViewHierarchyEvent(boolean started) {
- getMainCaptureSession().notifyViewHierarchyEvent(mId, started);
+ public void internalNotifyViewTreeEvent(boolean started) {
+ getMainCaptureSession().notifyViewTreeEvent(mId, started);
}
@Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 1dd1bee95c4b..2585b746583d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -79,8 +79,7 @@ public final class ContentCaptureEvent implements Parcelable {
* if the initial view hierarchy doesn't initially have any view that's important for content
* capture.
*/
- // TODO(b/125395044): change to TYPE_VIEW_TREE_APPEARING
- public static final int TYPE_INITIAL_VIEW_TREE_APPEARING = 4;
+ public static final int TYPE_VIEW_TREE_APPEARING = 4;
/**
* Called after events (such as {@link #TYPE_VIEW_APPEARED} and/or
@@ -90,8 +89,7 @@ public final class ContentCaptureEvent implements Parcelable {
* if the initial view hierarchy doesn't initially have any view that's important for content
* capture.
*/
- // TODO(b/125395044): change to TYPE_VIEW_TREE_APPEARED
- public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5;
+ public static final int TYPE_VIEW_TREE_APPEARED = 5;
/**
* Called after a call to
@@ -101,14 +99,29 @@ public final class ContentCaptureEvent implements Parcelable {
*/
public static final int TYPE_CONTEXT_UPDATED = 6;
+ /**
+ * Called after the session is ready, typically after the activity resumed and the
+ * initial views appeared
+ */
+ public static final int TYPE_SESSION_RESUMED = 7;
+
+ /**
+ * Called after the session is paused, typically after the activity paused and the
+ * views disappeared.
+ */
+ public static final int TYPE_SESSION_PAUSED = 8;
+
+
/** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_VIEW_APPEARED,
TYPE_VIEW_DISAPPEARED,
TYPE_VIEW_TEXT_CHANGED,
- TYPE_INITIAL_VIEW_TREE_APPEARING,
- TYPE_INITIAL_VIEW_TREE_APPEARED,
- TYPE_CONTEXT_UPDATED
+ TYPE_VIEW_TREE_APPEARING,
+ TYPE_VIEW_TREE_APPEARED,
+ TYPE_CONTEXT_UPDATED,
+ TYPE_SESSION_PAUSED,
+ TYPE_SESSION_RESUMED
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType{}
@@ -232,8 +245,9 @@ public final class ContentCaptureEvent implements Parcelable {
* Gets the type of the event.
*
* @return one of {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED},
- * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING},
- * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}, or {@link #TYPE_CONTEXT_UPDATED}.
+ * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_VIEW_TREE_APPEARING},
+ * {@link #TYPE_VIEW_TREE_APPEARED}, {@link #TYPE_CONTEXT_UPDATED},
+ * {@link #TYPE_SESSION_RESUMED}, or {@link #TYPE_SESSION_PAUSED}.
*/
public @EventType int getType() {
return mType;
@@ -413,15 +427,19 @@ public final class ContentCaptureEvent implements Parcelable {
return "SESSION_STARTED";
case TYPE_SESSION_FINISHED:
return "SESSION_FINISHED";
+ case TYPE_SESSION_RESUMED:
+ return "SESSION_RESUMED";
+ case TYPE_SESSION_PAUSED:
+ return "SESSION_PAUSED";
case TYPE_VIEW_APPEARED:
return "VIEW_APPEARED";
case TYPE_VIEW_DISAPPEARED:
return "VIEW_DISAPPEARED";
case TYPE_VIEW_TEXT_CHANGED:
return "VIEW_TEXT_CHANGED";
- case TYPE_INITIAL_VIEW_TREE_APPEARING:
+ case TYPE_VIEW_TREE_APPEARING:
return "VIEW_TREE_APPEARING";
- case TYPE_INITIAL_VIEW_TREE_APPEARED:
+ case TYPE_VIEW_TREE_APPEARED:
return "VIEW_TREE_APPEARED";
case TYPE_CONTEXT_UPDATED:
return "CONTEXT_UPDATED";
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index cdd4f35f538b..885bd2a39580 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -232,7 +232,7 @@ public final class ContentCaptureManager {
/** @hide */
@UiThread
- public void onActivityStarted(@NonNull IBinder applicationToken,
+ public void onActivityCreated(@NonNull IBinder applicationToken,
@NonNull ComponentName activityComponent, int flags) {
synchronized (mLock) {
mFlags |= flags;
@@ -242,7 +242,19 @@ public final class ContentCaptureManager {
/** @hide */
@UiThread
- public void onActivityStopped() {
+ public void onActivityResumed() {
+ getMainContentCaptureSession().notifySessionLifecycle(/* started= */ true);
+ }
+
+ /** @hide */
+ @UiThread
+ public void onActivityPaused() {
+ getMainContentCaptureSession().notifySessionLifecycle(/* started= */ false);
+ }
+
+ /** @hide */
+ @UiThread
+ public void onActivityDestroyed() {
getMainContentCaptureSession().destroy();
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 544a4f6dd386..ab8f346bdd2e 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -134,19 +134,19 @@ public abstract class ContentCaptureSession implements AutoCloseable {
/** @hide */
public static final int FLUSH_REASON_VIEW_ROOT_ENTERED = 2;
/** @hide */
- public static final int FLUSH_REASON_SESSION_STARTED = 4;
+ public static final int FLUSH_REASON_SESSION_STARTED = 3;
/** @hide */
- public static final int FLUSH_REASON_SESSION_FINISHED = 5;
+ public static final int FLUSH_REASON_SESSION_FINISHED = 4;
/** @hide */
- public static final int FLUSH_REASON_IDLE_TIMEOUT = 6;
+ public static final int FLUSH_REASON_IDLE_TIMEOUT = 5;
/** @hide */
@IntDef(prefix = { "FLUSH_REASON_" }, value = {
FLUSH_REASON_FULL,
+ FLUSH_REASON_VIEW_ROOT_ENTERED,
FLUSH_REASON_SESSION_STARTED,
FLUSH_REASON_SESSION_FINISHED,
- FLUSH_REASON_IDLE_TIMEOUT,
- FLUSH_REASON_VIEW_ROOT_ENTERED,
+ FLUSH_REASON_IDLE_TIMEOUT
})
@Retention(RetentionPolicy.SOURCE)
public @interface FlushReason{}
@@ -411,7 +411,7 @@ public abstract class ContentCaptureSession implements AutoCloseable {
@Nullable CharSequence text);
/** @hide */
- public abstract void internalNotifyViewHierarchyEvent(boolean started);
+ public abstract void internalNotifyViewTreeEvent(boolean started);
/**
* Creates a {@link ViewStructure} for a "standard" view.
@@ -501,14 +501,14 @@ public abstract class ContentCaptureSession implements AutoCloseable {
switch (reason) {
case FLUSH_REASON_FULL:
return "FULL";
+ case FLUSH_REASON_VIEW_ROOT_ENTERED:
+ return "VIEW_ROOT";
case FLUSH_REASON_SESSION_STARTED:
return "STARTED";
case FLUSH_REASON_SESSION_FINISHED:
return "FINISHED";
case FLUSH_REASON_IDLE_TIMEOUT:
return "IDLE";
- case FLUSH_REASON_VIEW_ROOT_ENTERED:
- return "ENTERED";
default:
return "UNKOWN-" + reason;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 14b2b28deaeb..dce8ebe66111 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -16,13 +16,15 @@
package android.view.contentcapture;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARING;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING;
import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
@@ -543,8 +545,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
@Override
- public void internalNotifyViewHierarchyEvent(boolean started) {
- notifyViewHierarchyEvent(mId, started);
+ public void internalNotifyViewTreeEvent(boolean started) {
+ notifyViewTreeEvent(mId, started);
}
@Override
@@ -590,12 +592,17 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
/** Public because is also used by ViewRootImpl */
- public void notifyViewHierarchyEvent(@NonNull String sessionId, boolean started) {
- final int type = started ? TYPE_INITIAL_VIEW_TREE_APPEARING
- : TYPE_INITIAL_VIEW_TREE_APPEARED;
+ public void notifyViewTreeEvent(@NonNull String sessionId, boolean started) {
+ final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
}
+ /** Public because is also used by ViewRootImpl */
+ public void notifySessionLifecycle(boolean started) {
+ final int type = started ? TYPE_SESSION_RESUMED : TYPE_SESSION_PAUSED;
+ sendEvent(new ContentCaptureEvent(mId, type), FORCE_FLUSH);
+ }
+
void notifyContextUpdated(@NonNull String sessionId,
@Nullable ContentCaptureContext context) {
sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 4d917a1b1968..efdc968909ee 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -16,6 +16,7 @@
package android.view.textclassifier;
+import android.annotation.Nullable;
import android.app.Person;
import android.content.Context;
import android.text.TextUtils;
@@ -110,6 +111,19 @@ public final class ActionsSuggestionsHelper {
SelectionSessionLogger.CLASSIFIER_ID, modelName, hash);
}
+ /**
+ * Returns a {@link android.view.textclassifier.LabeledIntent.TitleChooser} for
+ * conversation actions use case.
+ */
+ @Nullable
+ public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
+ if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
+ return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI
+ ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity;
+ }
+ return null;
+ }
+
private static final class PersonEncoder {
private final Map<Person, Integer> mMapping = new ArrayMap<>();
private int mNextUserId = FIRST_NON_LOCAL_USER;
diff --git a/core/java/android/view/textclassifier/IntentFactory.java b/core/java/android/view/textclassifier/IntentFactory.java
index 9f3b97f8339f..722c812856d4 100644
--- a/core/java/android/view/textclassifier/IntentFactory.java
+++ b/core/java/android/view/textclassifier/IntentFactory.java
@@ -32,7 +32,7 @@ public interface IntentFactory {
/**
* Return a list of LabeledIntent from the classification result.
*/
- List<TextClassifierImpl.LabeledIntent> create(
+ List<LabeledIntent> create(
Context context,
String text,
boolean foreignText,
@@ -43,9 +43,10 @@ public interface IntentFactory {
* Inserts translate action to the list if it is a foreign text.
*/
static void insertTranslateAction(
- List<TextClassifierImpl.LabeledIntent> actions, Context context, String text) {
- actions.add(new TextClassifierImpl.LabeledIntent(
+ List<LabeledIntent> actions, Context context, String text) {
+ actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.translate),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.translate_desc),
new Intent(Intent.ACTION_TRANSLATE)
// TODO: Probably better to introduce a "translate" scheme instead of
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/LabeledIntent.java
new file mode 100644
index 000000000000..7544dc1b58b1
--- /dev/null
+++ b/core/java/android/view/textclassifier/LabeledIntent.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.textclassifier;
+
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helper class to store the information from which RemoteActions are built.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class LabeledIntent {
+ private static final String TAG = "LabeledIntent";
+ public static final int DEFAULT_REQUEST_CODE = 0;
+ private static final TitleChooser DEFAULT_TITLE_CHOOSER =
+ (labeledIntent, resolveInfo) -> {
+ if (!TextUtils.isEmpty(labeledIntent.titleWithEntity)) {
+ return labeledIntent.titleWithEntity;
+ }
+ return labeledIntent.titleWithoutEntity;
+ };
+
+ @Nullable
+ public final String titleWithoutEntity;
+ @Nullable
+ public final String titleWithEntity;
+ public final String description;
+ // Do not update this intent.
+ public final Intent intent;
+ public final int requestCode;
+
+ /**
+ * Initializes a LabeledIntent.
+ *
+ * <p>NOTE: {@code requestCode} is required to not be {@link #DEFAULT_REQUEST_CODE}
+ * if distinguishing info (e.g. the classified text) is represented in intent extras only.
+ * In such circumstances, the request code should represent the distinguishing info
+ * (e.g. by generating a hashcode) so that the generated PendingIntent is (somewhat)
+ * unique. To be correct, the PendingIntent should be definitely unique but we try a
+ * best effort approach that avoids spamming the system with PendingIntents.
+ */
+ // TODO: Fix the issue mentioned above so the behaviour is correct.
+ public LabeledIntent(
+ @Nullable String titleWithoutEntity,
+ @Nullable String titleWithEntity,
+ String description,
+ Intent intent,
+ int requestCode) {
+ if (TextUtils.isEmpty(titleWithEntity) && TextUtils.isEmpty(titleWithoutEntity)) {
+ throw new IllegalArgumentException(
+ "titleWithEntity and titleWithoutEntity should not be both null");
+ }
+ this.titleWithoutEntity = titleWithoutEntity;
+ this.titleWithEntity = titleWithEntity;
+ this.description = Preconditions.checkNotNull(description);
+ this.intent = Preconditions.checkNotNull(intent);
+ this.requestCode = requestCode;
+ }
+
+ /**
+ * Return the resolved result.
+ */
+ @Nullable
+ public Result resolve(
+ Context context, @Nullable TitleChooser titleChooser) {
+ final PackageManager pm = context.getPackageManager();
+ final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+ final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
+ ? resolveInfo.activityInfo.packageName : null;
+ Icon icon = null;
+ Intent resolvedIntent = new Intent(intent);
+ boolean shouldShowIcon = false;
+ if (packageName != null && !"android".equals(packageName)) {
+ // There is a default activity handling the intent.
+ resolvedIntent.setComponent(
+ new ComponentName(packageName, resolveInfo.activityInfo.name));
+ if (resolveInfo.activityInfo.getIconResource() != 0) {
+ icon = Icon.createWithResource(
+ packageName, resolveInfo.activityInfo.getIconResource());
+ shouldShowIcon = true;
+ }
+ }
+ if (icon == null) {
+ // RemoteAction requires that there be an icon.
+ icon = Icon.createWithResource("android",
+ com.android.internal.R.drawable.ic_more_items);
+ }
+ final PendingIntent pendingIntent =
+ TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
+ if (pendingIntent == null) {
+ return null;
+ }
+ if (titleChooser == null) {
+ titleChooser = DEFAULT_TITLE_CHOOSER;
+ }
+ CharSequence title = titleChooser.chooseTitle(this, resolveInfo);
+ if (TextUtils.isEmpty(title)) {
+ Log.w(TAG, "Custom titleChooser return null, fallback to the default titleChooser");
+ title = DEFAULT_TITLE_CHOOSER.chooseTitle(this, resolveInfo);
+ }
+ final RemoteAction action =
+ new RemoteAction(icon, title, description, pendingIntent);
+ action.setShouldShowIcon(shouldShowIcon);
+ return new Result(resolvedIntent, action);
+ }
+
+ /**
+ * Data class that holds the result.
+ */
+ public static final class Result {
+ public final Intent resolvedIntent;
+ public final RemoteAction remoteAction;
+
+ public Result(Intent resolvedIntent, RemoteAction remoteAction) {
+ this.resolvedIntent = Preconditions.checkNotNull(resolvedIntent);
+ this.remoteAction = Preconditions.checkNotNull(remoteAction);
+ }
+ }
+
+ /**
+ * An object to choose a title from resolved info. If {@code null} is returned,
+ * {@link #titleWithEntity} will be used if it exists, {@link #titleWithoutEntity} otherwise.
+ */
+ public interface TitleChooser {
+ /**
+ * Picks a title from a {@link LabeledIntent} by looking into resolved info.
+ */
+ @Nullable
+ CharSequence chooseTitle(LabeledIntent labeledIntent, ResolveInfo resolveInfo);
+ }
+}
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/LegacyIntentFactory.java
index 2d0d032cfef3..ea9229d28814 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/LegacyIntentFactory.java
@@ -29,7 +29,6 @@ import android.os.UserManager;
import android.provider.Browser;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
-import android.view.textclassifier.TextClassifierImpl.LabeledIntent;
import com.google.android.textclassifier.AnnotatorModel;
@@ -100,8 +99,7 @@ public final class LegacyIntentFactory implements IntentFactory {
IntentFactory.insertTranslateAction(actions, context, text);
}
actions.forEach(
- action -> action.getIntent()
- .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
+ action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
return actions;
}
@@ -110,12 +108,14 @@ public final class LegacyIntentFactory implements IntentFactory {
final List<LabeledIntent> actions = new ArrayList<>();
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.email),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.email_desc),
new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("mailto:%s", text))),
LabeledIntent.DEFAULT_REQUEST_CODE));
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.add_contact),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.add_contact_desc),
new Intent(Intent.ACTION_INSERT_OR_EDIT)
.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
@@ -133,6 +133,7 @@ public final class LegacyIntentFactory implements IntentFactory {
if (!userRestrictions.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS, false)) {
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.dial),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.dial_desc),
new Intent(Intent.ACTION_DIAL).setData(
Uri.parse(String.format("tel:%s", text))),
@@ -140,6 +141,7 @@ public final class LegacyIntentFactory implements IntentFactory {
}
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.add_contact),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.add_contact_desc),
new Intent(Intent.ACTION_INSERT_OR_EDIT)
.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
@@ -148,6 +150,7 @@ public final class LegacyIntentFactory implements IntentFactory {
if (!userRestrictions.getBoolean(UserManager.DISALLOW_SMS, false)) {
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.sms),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.sms_desc),
new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("smsto:%s", text))),
@@ -163,6 +166,7 @@ public final class LegacyIntentFactory implements IntentFactory {
final String encText = URLEncoder.encode(text, "UTF-8");
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.map),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.map_desc),
new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(String.format("geo:0,0?q=%s", encText))),
@@ -181,6 +185,7 @@ public final class LegacyIntentFactory implements IntentFactory {
final List<LabeledIntent> actions = new ArrayList<>();
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.browse),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.browse_desc),
new Intent(Intent.ACTION_VIEW)
.setDataAndNormalize(Uri.parse(text))
@@ -211,6 +216,7 @@ public final class LegacyIntentFactory implements IntentFactory {
final List<LabeledIntent> actions = new ArrayList<>();
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.view_flight),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.view_flight_desc),
new Intent(Intent.ACTION_WEB_SEARCH)
.putExtra(SearchManager.QUERY, text),
@@ -225,6 +231,7 @@ public final class LegacyIntentFactory implements IntentFactory {
ContentUris.appendId(builder, parsedTime.toEpochMilli());
return new LabeledIntent(
context.getString(com.android.internal.R.string.view_calendar),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.view_calendar_desc),
new Intent(Intent.ACTION_VIEW).setData(builder.build()),
LabeledIntent.DEFAULT_REQUEST_CODE);
@@ -236,6 +243,7 @@ public final class LegacyIntentFactory implements IntentFactory {
final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
return new LabeledIntent(
context.getString(com.android.internal.R.string.add_calendar_event),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.add_calendar_event_desc),
new Intent(Intent.ACTION_INSERT)
.setData(CalendarContract.Events.CONTENT_URI)
@@ -252,6 +260,7 @@ public final class LegacyIntentFactory implements IntentFactory {
final List<LabeledIntent> actions = new ArrayList<>();
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.define),
+ /* titleWithEntity */ null,
context.getString(com.android.internal.R.string.define_desc),
new Intent(Intent.ACTION_DEFINE)
.putExtra(Intent.EXTRA_TEXT, text),
diff --git a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
index 2467802ec5a8..ed0259f4cd1a 100644
--- a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
@@ -48,12 +48,12 @@ public final class TemplateClassificationIntentFactory implements IntentFactory
}
/**
- * Returns a list of {@link android.view.textclassifier.TextClassifierImpl.LabeledIntent}
+ * Returns a list of {@link android.view.textclassifier.LabeledIntent}
* that are constructed from the classification result.
*/
@NonNull
@Override
- public List<TextClassifierImpl.LabeledIntent> create(
+ public List<LabeledIntent> create(
Context context,
String text,
boolean foreignText,
@@ -68,7 +68,7 @@ public final class TemplateClassificationIntentFactory implements IntentFactory
Log.w(TAG, "RemoteActionTemplate is missing, fallback to LegacyIntentFactory.");
return mFallback.create(context, text, foreignText, referenceTime, classification);
}
- final List<TextClassifierImpl.LabeledIntent> labeledIntents =
+ final List<LabeledIntent> labeledIntents =
mTemplateIntentFactory.create(remoteActionTemplates);
if (foreignText) {
IntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/TemplateIntentFactory.java
index 95f88c7de146..0696d98f1929 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateIntentFactory.java
@@ -42,29 +42,29 @@ public final class TemplateIntentFactory {
private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
@NonNull
- public List<TextClassifierImpl.LabeledIntent> create(
+ public List<LabeledIntent> create(
@Nullable RemoteActionTemplate[] remoteActionTemplates) {
if (ArrayUtils.isEmpty(remoteActionTemplates)) {
return Collections.emptyList();
}
- final List<TextClassifierImpl.LabeledIntent> labeledIntents = new ArrayList<>();
+ final List<LabeledIntent> labeledIntents = new ArrayList<>();
for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
if (!isValidTemplate(remoteActionTemplate)) {
Log.w(TAG, "Invalid RemoteActionTemplate skipped.");
continue;
}
labeledIntents.add(
- new TextClassifierImpl.LabeledIntent(
- remoteActionTemplate.title,
+ new LabeledIntent(
+ remoteActionTemplate.titleWithoutEntity,
+ remoteActionTemplate.titleWithEntity,
remoteActionTemplate.description,
createIntent(remoteActionTemplate),
remoteActionTemplate.requestCode == null
- ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
+ ? LabeledIntent.DEFAULT_REQUEST_CODE
: remoteActionTemplate.requestCode));
}
labeledIntents.forEach(
- action -> action.getIntent()
- .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
+ action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
return labeledIntents;
}
@@ -73,7 +73,8 @@ public final class TemplateIntentFactory {
Log.w(TAG, "Invalid RemoteActionTemplate: is null");
return false;
}
- if (TextUtils.isEmpty(remoteActionTemplate.title)) {
+ if (TextUtils.isEmpty(remoteActionTemplate.titleWithEntity)
+ && TextUtils.isEmpty(remoteActionTemplate.titleWithoutEntity)) {
Log.w(TAG, "Invalid RemoteActionTemplate: title is null");
return false;
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index e628f19668ae..632328be973e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -19,21 +19,14 @@ package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
-import android.app.PendingIntent;
import android.app.RemoteAction;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Icon;
import android.icu.util.ULocale;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -430,7 +423,12 @@ public final class TextClassifierImpl implements TextClassifier {
// Given that we only support implicit intent here, we should expect there is just one
// intent for each action type.
if (!labeledIntents.isEmpty()) {
- remoteAction = labeledIntents.get(0).asRemoteAction(mContext);
+ LabeledIntent.TitleChooser titleChooser =
+ ActionsSuggestionsHelper.createTitleChooser(actionType);
+ LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
+ if (result != null) {
+ remoteAction = result.remoteAction;
+ }
}
conversationActions.add(
new ConversationAction.Builder(actionType)
@@ -593,23 +591,26 @@ public final class TextClassifierImpl implements TextClassifier {
foreignLanguageBundle != null,
referenceTime,
highestScoringResult);
+ LabeledIntent.TitleChooser titleChooser =
+ (labeledIntent, resolveInfo) -> labeledIntent.titleWithoutEntity;
for (LabeledIntent labeledIntent : labeledIntents) {
- final RemoteAction action = labeledIntent.asRemoteAction(mContext);
- if (action == null) {
+ LabeledIntent.Result result = labeledIntent.resolve(mContext, titleChooser);
+ if (result == null) {
continue;
}
+ final RemoteAction action = result.remoteAction;
if (isPrimaryAction) {
// For O backwards compatibility, the first RemoteAction is also written to the
// legacy API fields.
builder.setIcon(action.getIcon().loadDrawable(mContext));
builder.setLabel(action.getTitle().toString());
- builder.setIntent(labeledIntent.getIntent());
+ builder.setIntent(result.resolvedIntent);
builder.setOnClickListener(TextClassification.createIntentOnClickListener(
TextClassification.createPendingIntent(mContext,
- labeledIntent.getIntent(), labeledIntent.getRequestCode())));
+ result.resolvedIntent, labeledIntent.requestCode)));
isPrimaryAction = false;
}
- builder.addAction(action, labeledIntent.getIntent());
+ builder.addAction(action, result.resolvedIntent);
}
return builder.setId(createId(text, start, end)).build();
@@ -737,89 +738,5 @@ public final class TextClassifierImpl implements TextClassifier {
return LocaleList.getDefault().get(0).toLanguageTag();
}
}
-
- /**
- * Helper class to store the information from which RemoteActions are built.
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- public static final class LabeledIntent {
-
- static final int DEFAULT_REQUEST_CODE = 0;
-
- private final String mTitle;
- private final String mDescription;
- private final Intent mIntent;
- private final int mRequestCode;
-
- /**
- * Initializes a LabeledIntent.
- *
- * <p>NOTE: {@code reqestCode} is required to not be {@link #DEFAULT_REQUEST_CODE}
- * if distinguishing info (e.g. the classified text) is represented in intent extras only.
- * In such circumstances, the request code should represent the distinguishing info
- * (e.g. by generating a hashcode) so that the generated PendingIntent is (somewhat)
- * unique. To be correct, the PendingIntent should be definitely unique but we try a
- * best effort approach that avoids spamming the system with PendingIntents.
- */
- // TODO: Fix the issue mentioned above so the behaviour is correct.
- LabeledIntent(String title, String description, Intent intent, int requestCode) {
- mTitle = title;
- mDescription = description;
- mIntent = intent;
- mRequestCode = requestCode;
- }
-
- @VisibleForTesting
- public String getTitle() {
- return mTitle;
- }
-
- @VisibleForTesting
- public String getDescription() {
- return mDescription;
- }
-
- @VisibleForTesting
- public Intent getIntent() {
- return mIntent;
- }
-
- @VisibleForTesting
- public int getRequestCode() {
- return mRequestCode;
- }
-
- @Nullable
- RemoteAction asRemoteAction(Context context) {
- final PackageManager pm = context.getPackageManager();
- final ResolveInfo resolveInfo = pm.resolveActivity(mIntent, 0);
- final String packageName = resolveInfo != null && resolveInfo.activityInfo != null
- ? resolveInfo.activityInfo.packageName : null;
- Icon icon = null;
- boolean shouldShowIcon = false;
- if (packageName != null && !"android".equals(packageName)) {
- // There is a default activity handling the intent.
- mIntent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
- if (resolveInfo.activityInfo.getIconResource() != 0) {
- icon = Icon.createWithResource(
- packageName, resolveInfo.activityInfo.getIconResource());
- shouldShowIcon = true;
- }
- }
- if (icon == null) {
- // RemoteAction requires that there be an icon.
- icon = Icon.createWithResource("android",
- com.android.internal.R.drawable.ic_more_items);
- }
- final PendingIntent pendingIntent =
- TextClassification.createPendingIntent(context, mIntent, mRequestCode);
- if (pendingIntent == null) {
- return null;
- }
- final RemoteAction action = new RemoteAction(icon, mTitle, mDescription, pendingIntent);
- action.setShouldShowIcon(shouldShowIcon);
- return action;
- }
- }
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a6129b04d14f..f44c33178242 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -312,7 +312,7 @@ public class GridView extends AbsListView {
* @return The view that is currently selected, if it happens to be in the
* range that we draw.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillDown(int pos, int nextTop) {
View selectedView = null;
@@ -412,7 +412,7 @@ public class GridView extends AbsListView {
*
* @return The view that is currently selected
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillUp(int pos, int nextBottom) {
View selectedView = null;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2aa019b5d0f4..2f44d6ee88b1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -782,7 +782,7 @@ public class ListView extends AbsListView {
* @return The view that is currently selected, if it happens to be in the
* range that we draw.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillDown(int pos, int nextTop) {
View selectedView = null;
@@ -817,7 +817,7 @@ public class ListView extends AbsListView {
*
* @return The view that is currently selected
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillUp(int pos, int nextBottom) {
View selectedView = null;
@@ -1490,7 +1490,7 @@ public class ListView extends AbsListView {
* @return The selected view, or null if the selected view is outside the
* visible area.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillSpecific(int position, int top) {
boolean tempIsSelected = position == mSelectedPosition;
View temp = makeAndAddView(position, top, true, mListPadding.left, tempIsSelected);
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 49c01237f2cc..b7cdad2d5e51 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -1062,7 +1062,6 @@ public final class Magnifier {
return;
}
synchronized (mLock) {
- mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
// Show or move the window at the content draw frame.
SurfaceControl.openTransaction();
mSurfaceControl.deferTransactionUntil(mSurface, frame);
@@ -1077,6 +1076,7 @@ public final class Magnifier {
}
}
};
+ mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
} else {
callback = null;
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
new file mode 100644
index 000000000000..5b778d2a6acd
--- /dev/null
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -0,0 +1,49 @@
+/**
+ * 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.config.sysui;
+
+/**
+ * Keeps the flags related to the SystemUI namespace in {@link DeviceConfig}.
+ *
+ * @hide
+ */
+public final class SystemUiDeviceConfigFlags {
+
+ /**
+ * Whether the Notification Assistant should generate replies for notifications.
+ */
+ public static final String NAS_GENERATE_REPLIES = "nas_generate_replies";
+
+ /**
+ * Whether the Notification Assistant should generate contextual actions for notifications.
+ */
+ public static final String NAS_GENERATE_ACTIONS = "nas_generate_actions";
+
+ /**
+ * The maximum number of messages the Notification Assistant should extract from a
+ * conversation when constructing responses for that conversation.
+ */
+ public static final String NAS_MAX_MESSAGES_TO_EXTRACT = "nas_max_messages_to_extract";
+
+ /**
+ * The maximum number of suggestions the Notification Assistant should provide for a
+ * messaging conversation.
+ */
+ public static final String NAS_MAX_SUGGESTIONS = "nas_max_suggestions";
+
+ private SystemUiDeviceConfigFlags() { }
+}
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 2c78be779170..bab478748467 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -568,7 +568,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
/**
- * Aggregated data by uid/class/method to be sent through WestWorld.
+ * Aggregated data by uid/class/method to be sent through statsd.
*/
public static class ExportedCallStat {
public int callingUid;
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 0604ab2f7237..58b48d88fa38 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -162,9 +162,9 @@ public final class Zygote {
/**
* The duration to wait before re-checking Zygote related system properties.
*
- * Five minutes in milliseconds.
+ * One minute in milliseconds.
*/
- public static final long PROPERTY_CHECK_INTERVAL = 300000;
+ public static final long PROPERTY_CHECK_INTERVAL = 60000;
/**
* @hide for internal use only
@@ -236,14 +236,14 @@ public final class Zygote {
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- String packageName, String[] packagesForUID, String[] visibleVolIDs, String sandboxId) {
+ String packageName, String[] packagesForUID, String sandboxId) {
ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName,
- packagesForUID, visibleVolIDs, sandboxId);
+ packagesForUID, sandboxId);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
@@ -258,7 +258,7 @@ public final class Zygote {
private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
- String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs,
+ String appDataDir, String packageName, String[] packagesForUID,
String sandboxId);
/**
@@ -285,11 +285,11 @@ public final class Zygote {
public static void specializeBlastula(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
- String[] packagesForUID, String[] visibleVolIDs, String sandboxId) {
+ String[] packagesForUID, String sandboxId) {
nativeSpecializeBlastula(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
niceName, startChildZygote, instructionSet, appDataDir,
- packageName, packagesForUID, visibleVolIDs, sandboxId);
+ packageName, packagesForUID, sandboxId);
// Enable tracing as soon as possible for the child process.
Trace.setTracingEnabled(true, runtimeFlags);
@@ -309,7 +309,7 @@ public final class Zygote {
private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
- String[] packagesForUID, String[] visibleVolIDs, String sandboxId);
+ String[] packagesForUID, String sandboxId);
/**
* Called to do any initialization before starting an application.
@@ -427,6 +427,12 @@ public final class Zygote {
defaultValue);
}
+ protected static void emptyBlastulaPool() {
+ nativeEmptyBlastulaPool();
+ }
+
+ private static native void nativeEmptyBlastulaPool();
+
/**
* Returns the value of a system property converted to a boolean using specific logic.
*
@@ -520,7 +526,7 @@ public final class Zygote {
LocalSocket sessionSocket = null;
DataOutputStream blastulaOutputStream = null;
Credentials peerCredentials = null;
- String[] argStrings = null;
+ ZygoteArguments args = null;
while (true) {
try {
@@ -533,25 +539,24 @@ public final class Zygote {
peerCredentials = sessionSocket.getPeerCredentials();
- argStrings = readArgumentList(blastulaReader);
+ String[] argStrings = readArgumentList(blastulaReader);
if (argStrings != null) {
+ args = new ZygoteArguments(argStrings);
+
+ // TODO (chriswailes): Should this only be run for debug builds?
+ validateBlastulaCommand(args);
break;
} else {
Log.e("Blastula", "Truncated command received.");
IoUtils.closeQuietly(sessionSocket);
}
- } catch (IOException ioEx) {
- Log.e("Blastula", "Failed to read command: " + ioEx.getMessage());
+ } catch (Exception ex) {
+ Log.e("Blastula", ex.getMessage());
IoUtils.closeQuietly(sessionSocket);
}
}
- ZygoteArguments args = new ZygoteArguments(argStrings);
-
- // TODO (chriswailes): Should this only be run for debug builds?
- validateBlastulaCommand(args);
-
applyUidSecurityPolicy(args, peerCredentials);
applyDebuggerSystemProperty(args);
@@ -600,7 +605,7 @@ public final class Zygote {
args.mRuntimeFlags, rlimits, args.mMountExternal,
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
args.mInstructionSet, args.mAppDataDir, args.mPackageName,
- args.mPackagesForUid, args.mVisibleVolIds, args.mSandboxId);
+ args.mPackagesForUid, args.mSandboxId);
if (args.mNiceName != null) {
Process.setArgV0(args.mNiceName);
@@ -740,8 +745,8 @@ public final class Zygote {
if (args.mInvokeWith != null && peerUid != 0
&& (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
- throw new ZygoteSecurityException("Peer is permitted to specify an"
- + "explicit invoke-with wrapper command only for debuggable"
+ throw new ZygoteSecurityException("Peer is permitted to specify an "
+ + "explicit invoke-with wrapper command only for debuggable "
+ "applications.");
}
}
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index c24a9e084293..9cb5820a32ce 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -101,6 +101,12 @@ class ZygoteArguments {
String mSeInfo;
/**
+ *
+ */
+ boolean mBlastulaPoolEnabled;
+ boolean mBlastulaPoolStatusSpecified = false;
+
+ /**
* from all --rlimit=r,c,m
*/
ArrayList<int[]> mRLimits;
@@ -116,9 +122,6 @@ class ZygoteArguments {
/** from --packages-for-uid */
String[] mPackagesForUid;
- /** from --visible-vols */
- String[] mVisibleVolIds;
-
/** from --sandbox-id */
String mSandboxId;
@@ -395,13 +398,15 @@ class ZygoteArguments {
mPackageName = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--packages-for-uid=")) {
mPackagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
- } else if (arg.startsWith("--visible-vols=")) {
- mVisibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");
} else if (arg.startsWith("--sandbox-id=")) {
if (mSandboxId != null) {
throw new IllegalArgumentException("Duplicate arg specified");
}
mSandboxId = arg.substring(arg.indexOf('=') + 1);
+ } else if (arg.startsWith("--blastula-pool-enabled=")) {
+ mBlastulaPoolStatusSpecified = true;
+ mBlastulaPoolEnabled = Boolean.parseBoolean(arg.substring(arg.indexOf('=') + 1));
+ expectRuntimeArgs = false;
} else {
break;
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 8a878e22a7e3..c7ba22df5700 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -158,6 +158,10 @@ class ZygoteConnection {
return null;
}
+ if (parsedArgs.mBlastulaPoolStatusSpecified) {
+ return handleBlastulaPoolStatusChange(zygoteServer, parsedArgs.mBlastulaPoolEnabled);
+ }
+
if (parsedArgs.mPreloadDefault) {
handlePreload();
return null;
@@ -185,13 +189,12 @@ class ZygoteConnection {
}
if (parsedArgs.mApiBlacklistExemptions != null) {
- handleApiBlacklistExemptions(parsedArgs.mApiBlacklistExemptions);
- return null;
+ return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
}
if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
- handleHiddenApiAccessLogSampleRate(parsedArgs.mHiddenApiAccessLogSampleRate);
- return null;
+ return handleHiddenApiAccessLogSampleRate(zygoteServer,
+ parsedArgs.mHiddenApiAccessLogSampleRate);
}
if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
@@ -258,7 +261,7 @@ class ZygoteConnection {
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName,
- parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds, parsedArgs.mSandboxId);
+ parsedArgs.mPackagesForUid, parsedArgs.mSandboxId);
try {
if (pid == 0) {
@@ -325,10 +328,64 @@ class ZygoteConnection {
}
}
- private void handleApiBlacklistExemptions(String[] exemptions) {
+ private Runnable stateChangeWithBlastulaPoolReset(ZygoteServer zygoteServer,
+ Runnable stateChangeCode) {
try {
- ZygoteInit.setApiBlacklistExemptions(exemptions);
+ if (zygoteServer.isBlastulaPoolEnabled()) {
+ Zygote.emptyBlastulaPool();
+ }
+
+ stateChangeCode.run();
+
+ if (zygoteServer.isBlastulaPoolEnabled()) {
+ Runnable fpResult =
+ zygoteServer.fillBlastulaPool(
+ new int[]{mSocket.getFileDescriptor().getInt$()});
+
+ if (fpResult != null) {
+ zygoteServer.setForkChild();
+ return fpResult;
+ }
+ }
+
mSocketOutStream.writeInt(0);
+
+ return null;
+ } catch (IOException ioe) {
+ throw new IllegalStateException("Error writing to command socket", ioe);
+ }
+ }
+
+ /**
+ * Makes the necessary changes to implement a new API blacklist exemption policy, and then
+ * responds to the system server, letting it know that the task has been completed.
+ *
+ * This necessitates a change to the internal state of the Zygote. As such, if the blastula
+ * pool is enabled all existing blastulas have an incorrect API blacklist exemption list. To
+ * properly handle this request the pool must be emptied and refilled. This process can return
+ * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
+ *
+ * @param zygoteServer The server object that received the request
+ * @param exemptions The new exemption list.
+ * @return A Runnable object representing a new app in any blastulas spawned from here; the
+ * zygote process will always receive a null value from this function.
+ */
+ private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
+ return stateChangeWithBlastulaPoolReset(zygoteServer,
+ () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
+ }
+
+ private Runnable handleBlastulaPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
+ try {
+ Runnable fpResult = zygoteServer.setBlastulaPoolStatus(newStatus, mSocket);
+
+ if (fpResult == null) {
+ mSocketOutStream.writeInt(0);
+ } else {
+ zygoteServer.setForkChild();
+ }
+
+ return fpResult;
} catch (IOException ioe) {
throw new IllegalStateException("Error writing to command socket", ioe);
}
@@ -384,15 +441,26 @@ class ZygoteConnection {
}
}
- private void handleHiddenApiAccessLogSampleRate(int samplingRate) {
- try {
+ /**
+ * Changes the API access log sample rate for the Zygote and processes spawned from it.
+ *
+ * This necessitates a change to the internal state of the Zygote. As such, if the blastula
+ * pool is enabled all existing blastulas have an incorrect API access log sample rate. To
+ * properly handle this request the pool must be emptied and refilled. This process can return
+ * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
+ *
+ * @param zygoteServer The server object that received the request
+ * @param samplingRate The new sample rate
+ * @return A Runnable object representing a new app in any blastulas spawned from here; the
+ * zygote process will always receive a null value from this function.
+ */
+ private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
+ int samplingRate) {
+ return stateChangeWithBlastulaPoolReset(zygoteServer, () -> {
ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
HiddenApiUsageLogger.setHiddenApiAccessLogSampleRate(samplingRate);
ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
- mSocketOutStream.writeInt(0);
- } catch (IOException ioe) {
- throw new IllegalStateException("Error writing to command socket", ioe);
- }
+ });
}
protected void preload() {
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 2c17540eb6c6..c4c98baf0e4c 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -68,6 +68,15 @@ class ZygoteServer {
private static final String BLASTULA_POOL_SIZE_MIN_DEFAULT = "1";
/**
+ * Indicates if this Zygote server can support a blastula pool. Currently this should only be
+ * true for the primary and secondary Zygotes, and not the App Zygotes or the WebView Zygote.
+ *
+ * TODO (chriswailes): Make this an explicit argument to the constructor
+ */
+
+ private final boolean mBlastulaPoolSupported;
+
+ /**
* If the blastula pool should be created and used to start applications.
*
* Setting this value to false will disable the creation, maintenance, and use of the blastula
@@ -127,6 +136,8 @@ class ZygoteServer {
mBlastulaPoolEventFD = null;
mZygoteSocket = null;
mBlastulaPoolSocket = null;
+
+ mBlastulaPoolSupported = false;
}
/**
@@ -151,12 +162,18 @@ class ZygoteServer {
}
fetchBlastulaPoolPolicyProps();
+
+ mBlastulaPoolSupported = true;
}
void setForkChild() {
mIsForkChild = true;
}
+ public boolean isBlastulaPoolEnabled() {
+ return mBlastulaPoolEnabled;
+ }
+
/**
* Registers a server socket for zygote command connections. This opens the server socket
* at the specified name in the abstract socket namespace.
@@ -224,42 +241,43 @@ class ZygoteServer {
}
private void fetchBlastulaPoolPolicyProps() {
- final String blastulaPoolSizeMaxPropString =
- Zygote.getSystemProperty(
- DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MAX,
- BLASTULA_POOL_SIZE_MAX_DEFAULT);
-
- if (!blastulaPoolSizeMaxPropString.isEmpty()) {
- mBlastulaPoolSizeMax =
- Integer.min(
- Integer.parseInt(blastulaPoolSizeMaxPropString),
- BLASTULA_POOL_SIZE_MAX_LIMIT);
- }
+ if (mBlastulaPoolSupported) {
+ final String blastulaPoolSizeMaxPropString =
+ Zygote.getSystemProperty(
+ DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MAX,
+ BLASTULA_POOL_SIZE_MAX_DEFAULT);
+
+ if (!blastulaPoolSizeMaxPropString.isEmpty()) {
+ mBlastulaPoolSizeMax =
+ Integer.min(
+ Integer.parseInt(blastulaPoolSizeMaxPropString),
+ BLASTULA_POOL_SIZE_MAX_LIMIT);
+ }
- final String blastulaPoolSizeMinPropString =
- Zygote.getSystemProperty(
- DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MIN,
- BLASTULA_POOL_SIZE_MIN_DEFAULT);
+ final String blastulaPoolSizeMinPropString =
+ Zygote.getSystemProperty(
+ DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MIN,
+ BLASTULA_POOL_SIZE_MIN_DEFAULT);
- if (!blastulaPoolSizeMinPropString.isEmpty()) {
- mBlastulaPoolSizeMin =
- Integer.max(
- Integer.parseInt(blastulaPoolSizeMinPropString),
- BLASTULA_POOL_SIZE_MIN_LIMIT);
- }
+ if (!blastulaPoolSizeMinPropString.isEmpty()) {
+ mBlastulaPoolSizeMin =
+ Integer.max(
+ Integer.parseInt(blastulaPoolSizeMinPropString),
+ BLASTULA_POOL_SIZE_MIN_LIMIT);
+ }
- final String blastulaPoolRefillThresholdPropString =
- Zygote.getSystemProperty(
- DeviceConfig.RuntimeNative.BLASTULA_POOL_REFILL_THRESHOLD,
- Integer.toString(mBlastulaPoolSizeMax / 2));
+ final String blastulaPoolRefillThresholdPropString =
+ Zygote.getSystemProperty(
+ DeviceConfig.RuntimeNative.BLASTULA_POOL_REFILL_THRESHOLD,
+ Integer.toString(mBlastulaPoolSizeMax / 2));
- if (!blastulaPoolRefillThresholdPropString.isEmpty()) {
- mBlastulaPoolRefillThreshold =
- Integer.min(
- Integer.parseInt(blastulaPoolRefillThresholdPropString),
- mBlastulaPoolSizeMax);
+ if (!blastulaPoolRefillThresholdPropString.isEmpty()) {
+ mBlastulaPoolRefillThreshold =
+ Integer.min(
+ Integer.parseInt(blastulaPoolRefillThresholdPropString),
+ mBlastulaPoolSizeMax);
+ }
}
-
}
private long mLastPropCheckTimestamp = 0;
@@ -282,44 +300,65 @@ class ZygoteServer {
* this function will return a Runnable object representing the new application that is
* passed up from blastulaMain.
*/
- private Runnable fillBlastulaPool(int[] sessionSocketRawFDs) {
- if (mBlastulaPoolEnabled) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillBlastulaPool");
- int blastulaPoolCount = Zygote.getBlastulaPoolCount();
- int numBlastulasToSpawn = mBlastulaPoolSizeMax - blastulaPoolCount;
+ Runnable fillBlastulaPool(int[] sessionSocketRawFDs) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillBlastulaPool");
- if (blastulaPoolCount < mBlastulaPoolSizeMin
- || numBlastulasToSpawn >= mBlastulaPoolRefillThreshold) {
+ int blastulaPoolCount = Zygote.getBlastulaPoolCount();
+ int numBlastulasToSpawn = mBlastulaPoolSizeMax - blastulaPoolCount;
- // Disable some VM functionality and reset some system values
- // before forking.
- ZygoteHooks.preFork();
- Zygote.resetNicePriority();
+ if (blastulaPoolCount < mBlastulaPoolSizeMin
+ || numBlastulasToSpawn >= mBlastulaPoolRefillThreshold) {
- while (blastulaPoolCount++ < mBlastulaPoolSizeMax) {
- Runnable caller = Zygote.forkBlastula(mBlastulaPoolSocket, sessionSocketRawFDs);
+ // Disable some VM functionality and reset some system values
+ // before forking.
+ ZygoteHooks.preFork();
+ Zygote.resetNicePriority();
- if (caller != null) {
- return caller;
- }
- }
-
- // Re-enable runtime services for the Zygote. Blastula services
- // are re-enabled in specializeBlastula.
- ZygoteHooks.postForkCommon();
+ while (blastulaPoolCount++ < mBlastulaPoolSizeMax) {
+ Runnable caller = Zygote.forkBlastula(mBlastulaPoolSocket, sessionSocketRawFDs);
- Log.i("zygote",
- "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn);
+ if (caller != null) {
+ return caller;
+ }
}
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ // Re-enable runtime services for the Zygote. Blastula services
+ // are re-enabled in specializeBlastula.
+ ZygoteHooks.postForkCommon();
+
+ Log.i("zygote",
+ "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn);
}
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
return null;
}
/**
+ * Empty or fill the blastula pool as dictated by the current and new blastula pool statuses.
+ */
+ Runnable setBlastulaPoolStatus(boolean newStatus, LocalSocket sessionSocket) {
+ if (!mBlastulaPoolSupported) {
+ Log.w(TAG,
+ "Attempting to enable a blastula pool for a Zygote that doesn't support it.");
+ return null;
+ } else if (mBlastulaPoolEnabled == newStatus) {
+ return null;
+ }
+
+ mBlastulaPoolEnabled = newStatus;
+
+ if (newStatus) {
+ return fillBlastulaPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
+ } else {
+ Zygote.emptyBlastulaPool();
+ return null;
+ }
+ }
+
+ /**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
@@ -334,12 +373,26 @@ class ZygoteServer {
while (true) {
fetchBlastulaPoolPolicyPropsWithMinInterval();
- int[] blastulaPipeFDs = Zygote.getBlastulaPipeFDs();
+ int[] blastulaPipeFDs = null;
+ StructPollfd[] pollFDs = null;
+
+ // Allocate enough space for the poll structs, taking into account
+ // the state of the blastula pool for this Zygote (could be a
+ // regular Zygote, a WebView Zygote, or an AppZygote).
+ if (mBlastulaPoolEnabled) {
+ blastulaPipeFDs = Zygote.getBlastulaPipeFDs();
+ pollFDs = new StructPollfd[socketFDs.size() + 1 + blastulaPipeFDs.length];
+ } else {
+ pollFDs = new StructPollfd[socketFDs.size()];
+ }
- // Space for all of the socket FDs, the Blastula Pool Event FD, and
- // all of the open blastula read pipe FDs.
- StructPollfd[] pollFDs =
- new StructPollfd[socketFDs.size() + 1 + blastulaPipeFDs.length];
+ /*
+ * For reasons of correctness the blastula pool pipe and event FDs
+ * must be processed before the session and server sockets. This
+ * is to ensure that the blastula pool accounting information is
+ * accurate when handling other requests like API blacklist
+ * exemptions.
+ */
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
@@ -350,19 +403,22 @@ class ZygoteServer {
}
final int blastulaPoolEventFDIndex = pollIndex;
- pollFDs[pollIndex] = new StructPollfd();
- pollFDs[pollIndex].fd = mBlastulaPoolEventFD;
- pollFDs[pollIndex].events = (short) POLLIN;
- ++pollIndex;
-
- for (int blastulaPipeFD : blastulaPipeFDs) {
- FileDescriptor managedFd = new FileDescriptor();
- managedFd.setInt$(blastulaPipeFD);
+ if (mBlastulaPoolEnabled) {
pollFDs[pollIndex] = new StructPollfd();
- pollFDs[pollIndex].fd = managedFd;
+ pollFDs[pollIndex].fd = mBlastulaPoolEventFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
+
+ for (int blastulaPipeFD : blastulaPipeFDs) {
+ FileDescriptor managedFd = new FileDescriptor();
+ managedFd.setInt$(blastulaPipeFD);
+
+ pollFDs[pollIndex] = new StructPollfd();
+ pollFDs[pollIndex].fd = managedFd;
+ pollFDs[pollIndex].events = (short) POLLIN;
+ ++pollIndex;
+ }
}
try {
@@ -371,6 +427,8 @@ class ZygoteServer {
throw new RuntimeException("poll failed", ex);
}
+ boolean blastulaPoolFDRead = false;
+
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
@@ -390,6 +448,7 @@ class ZygoteServer {
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
+ // TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
@@ -480,17 +539,22 @@ class ZygoteServer {
Zygote.removeBlastulaTableEntry((int) messagePayload);
}
- int[] sessionSocketRawFDs =
- socketFDs.subList(1, socketFDs.size())
+ blastulaPoolFDRead = true;
+ }
+ }
+
+ // Check to see if the blastula pool needs to be refilled.
+ if (blastulaPoolFDRead) {
+ int[] sessionSocketRawFDs =
+ socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(fd -> fd.getInt$())
.toArray();
- final Runnable command = fillBlastulaPool(sessionSocketRawFDs);
+ final Runnable command = fillBlastulaPool(sessionSocketRawFDs);
- if (command != null) {
- return command;
- }
+ if (command != null) {
+ return command;
}
}
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 9a77802aa541..1c5816c1578e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -36,17 +36,17 @@ interface ILockSettings {
boolean getBoolean(in String key, in boolean defaultValue, in int userId);
long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
- void setLockCredential(in String credential, int type, in String savedCredential, int requestedQuality, int userId);
+ void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
void resetKeyStore(int userId);
- VerifyCredentialResponse checkCredential(in String credential, int type, int userId,
+ VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
in ICheckCredentialProgressCallback progressCallback);
- VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId);
- VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId);
+ VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId);
+ VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
- byte[] getHashFactor(String currentCredential, int userId);
- void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword);
+ byte[] getHashFactor(in byte[] currentCredential, int userId);
+ void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword);
boolean getSeparateProfileChallengeEnabled(int userId);
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index 586ece0a274a..bda3b5728fdc 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -150,12 +150,33 @@ public final class LockPatternChecker {
* @param challenge The challenge to verify against the pattern.
* @param userId The user to check against the pattern.
* @param callback The callback to be invoked with the verification result.
+ *
+ * @deprecated Pass the password as a byte array.
*/
+ @Deprecated
public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
final String password,
final long challenge,
final int userId,
final OnVerifyCallback callback) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return verifyPassword(utils, passwordBytes, challenge, userId, callback);
+ }
+
+ /**
+ * Verify a password asynchronously.
+ *
+ * @param utils The LockPatternUtils instance to use.
+ * @param password The password to check.
+ * @param challenge The challenge to verify against the pattern.
+ * @param userId The user to check against the pattern.
+ * @param callback The callback to be invoked with the verification result.
+ */
+ public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
+ final byte[] password,
+ final long challenge,
+ final int userId,
+ final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
private int mThrottleTimeout;
@@ -188,7 +209,7 @@ public final class LockPatternChecker {
* @param callback The callback to be invoked with the verification result.
*/
public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils,
- final String password,
+ final byte[] password,
final boolean isPattern,
final long challenge,
final int userId,
@@ -222,18 +243,36 @@ public final class LockPatternChecker {
* @param password The password to check.
* @param userId The user to check against the pattern.
* @param callback The callback to be invoked with the check result.
+ * @deprecated Pass passwords as byte[]
*/
+ @Deprecated
public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
final String password,
final int userId,
final OnCheckCallback callback) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return checkPassword(utils, passwordBytes, userId, callback);
+ }
+
+ /**
+ * Checks a password asynchronously.
+ *
+ * @param utils The LockPatternUtils instance to use.
+ * @param passwordBytes The password to check.
+ * @param userId The user to check against the pattern.
+ * @param callback The callback to be invoked with the check result.
+ */
+ public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
+ final byte[] passwordBytes,
+ final int userId,
+ final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
private int mThrottleTimeout;
@Override
protected Boolean doInBackground(Void... args) {
try {
- return utils.checkPassword(password, userId, callback::onEarlyMatched);
+ return utils.checkPassword(passwordBytes, userId, callback::onEarlyMatched);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return false;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 8d3c482104f7..17ed2a0a048c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -67,6 +67,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.StringJoiner;
@@ -356,7 +357,7 @@ public class LockPatternUtils {
null /* componentName */, userId);
}
- private byte[] verifyCredential(String credential, int type, long challenge, int userId)
+ private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId)
throws RequestThrottledException {
try {
VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
@@ -373,7 +374,7 @@ public class LockPatternUtils {
}
}
- private boolean checkCredential(String credential, int type, int userId,
+ private boolean checkCredential(byte[] credential, int type, int userId,
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
try {
@@ -404,7 +405,7 @@ public class LockPatternUtils {
public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
throws RequestThrottledException {
throwIfCalledOnMainThread();
- return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
+ return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
userId);
}
@@ -429,7 +430,7 @@ public class LockPatternUtils {
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
throwIfCalledOnMainThread();
- return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
+ return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId,
progressCallback);
}
@@ -442,7 +443,7 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPassword(String password, long challenge, int userId)
+ public byte[] verifyPassword(byte[] password, long challenge, int userId)
throws RequestThrottledException {
throwIfCalledOnMainThread();
return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
@@ -458,7 +459,7 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
+ public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge,
int userId) throws RequestThrottledException {
throwIfCalledOnMainThread();
try {
@@ -480,16 +481,31 @@ public class LockPatternUtils {
}
/**
+ *
* Check to see if a password matches the saved password. If no password exists,
* always returns true.
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
public boolean checkPassword(String password, int userId) throws RequestThrottledException {
- return checkPassword(password, userId, null /* progressCallback */);
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return checkPassword(passwordBytes, userId, null /* progressCallback */);
}
+
/**
+ *
+ * Check to see if a password matches the saved password. If no password exists,
+ * always returns true.
+ * @param password The password to check.
+ * @return Whether the password matches the stored one.
+ */
+ public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException {
+ return checkPassword(password, userId, null /* progressCallback */);
+ }
+
+ // TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api
+ /* *
* Check to see if a password matches the saved password. If no password exists,
* always returns true.
* @param password The password to check.
@@ -498,6 +514,22 @@ public class LockPatternUtils {
public boolean checkPassword(String password, int userId,
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ throwIfCalledOnMainThread();
+ return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
+
+ }
+
+ /**
+ * Check to see if a password matches the saved password. If no password exists,
+ * always returns true.
+ * @param password The password to check.
+ * @return Whether the password matches the stored one.
+ */
+
+ public boolean checkPassword(byte[] password, int userId,
+ @Nullable CheckCredentialProgressCallback progressCallback)
+ throws RequestThrottledException {
throwIfCalledOnMainThread();
return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
}
@@ -519,7 +551,7 @@ public class LockPatternUtils {
* Returns the password history hash factor, needed to check new password against password
* history with {@link #checkPasswordHistory(String, byte[], int)}
*/
- public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
+ public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
try {
return getLockSettings().getHashFactor(currentPassword, userId);
} catch (RemoteException e) {
@@ -537,8 +569,8 @@ public class LockPatternUtils {
* {@link ILockSettings#getHashFactor}
* @return Whether the password matches any in the history.
*/
- public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
- if (TextUtils.isEmpty(passwordToCheck)) {
+ public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
+ if (passwordToCheck == null || passwordToCheck.length == 0) {
Log.e(TAG, "checkPasswordHistory: empty password");
return false;
}
@@ -639,13 +671,13 @@ public class LockPatternUtils {
/**
* Clear any lock pattern or password.
*/
- public void clearLock(String savedCredential, int userHandle) {
+ public void clearLock(byte[] savedCredential, int userHandle) {
final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
try{
- getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
- PASSWORD_QUALITY_UNSPECIFIED, userHandle);
+ getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
+ savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
} catch (Exception e) {
Log.e(TAG, "Failed to clear lock", e);
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
@@ -704,10 +736,11 @@ public class LockPatternUtils {
/**
* Save a lock pattern.
* @param pattern The new pattern to save.
- * @param savedPattern The previously saved pattern, converted to String format
+ * @param savedPattern The previously saved pattern, converted to byte[] format
* @param userId the user whose pattern is to be saved.
*/
- public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
+ public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
+ int userId) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
@@ -717,12 +750,12 @@ public class LockPatternUtils {
+ MIN_LOCK_PATTERN_SIZE + " dots long.");
}
- final String stringPattern = patternToString(pattern);
+ final byte[] bytePattern = patternToByteArray(pattern);
final int currentQuality = getKeyguardStoredPasswordQuality(userId);
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
try {
- getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
- savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
+ getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
+ PASSWORD_QUALITY_SOMETHING, userId);
} catch (Exception e) {
Log.e(TAG, "Couldn't save lock pattern", e);
setKeyguardStoredPasswordQuality(currentQuality, userId);
@@ -734,7 +767,7 @@ public class LockPatternUtils {
if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
} else {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern);
}
}
@@ -806,7 +839,7 @@ public class LockPatternUtils {
}
/** Update the encryption password if it is enabled **/
- private void updateEncryptionPassword(final int type, final String password) {
+ private void updateEncryptionPassword(final int type, final byte[] password) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
@@ -825,7 +858,9 @@ public class LockPatternUtils {
protected Void doInBackground(Void... dummy) {
IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
- storageManager.changeEncryptionPassword(type, password);
+ // TODO(b/120484642): This is a location where we still use a String for vold
+ String passwordString = password != null ? new String(password) : null;
+ storageManager.changeEncryptionPassword(type, passwordString);
} catch (RemoteException e) {
Log.e(TAG, "Error changing encryption password", e);
}
@@ -842,14 +877,34 @@ public class LockPatternUtils {
* @param savedPassword The previously saved lock password, or null if none
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
* @param userHandle The userId of the user to change the password for
+ *
+ * @deprecated Pass password as a byte array
*/
+ @Deprecated
public void saveLockPassword(String password, String savedPassword, int requestedQuality,
int userHandle) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
+ saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
+ }
+
+ /**
+ * Save a lock password. Does not ensure that the password is as good
+ * as the requested mode, but will adjust the mode to be as good as the
+ * password.
+ * @param password The password to save
+ * @param savedPassword The previously saved lock password, or null if none
+ * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
+ * android.content.ComponentName)}
+ * @param userHandle The userId of the user to change the password for
+ */
+ public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
+ int userHandle) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
- if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
+ if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must not be null and at least "
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
}
@@ -864,8 +919,8 @@ public class LockPatternUtils {
computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
userHandle);
try {
- getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
- savedPassword, requestedQuality, userHandle);
+ getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
+ requestedQuality, userHandle);
} catch (Exception e) {
Log.e(TAG, "Unable to save lock password", e);
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
@@ -882,7 +937,7 @@ public class LockPatternUtils {
* Update device encryption password if calling user is USER_SYSTEM and device supports
* encryption.
*/
- private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
+ private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) {
// Update the device encryption password.
if (userHandle == UserHandle.USER_SYSTEM
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
@@ -902,8 +957,8 @@ public class LockPatternUtils {
* Store the hash of the *current* password in the password history list, if device policy
* enforces password history requirement.
*/
- private void updatePasswordHistory(String password, int userHandle) {
- if (TextUtils.isEmpty(password)) {
+ private void updatePasswordHistory(byte[] password, int userHandle) {
+ if (password == null || password.length == 0) {
Log.e(TAG, "checkPasswordHistory: empty password");
return;
}
@@ -982,7 +1037,7 @@ public class LockPatternUtils {
* if DevicePolicyManager has a stronger quality requirement. This value will be written
* to PASSWORD_TYPE_KEY.
*/
- private int computePasswordQuality(int type, String credential, int requestedQuality) {
+ private int computePasswordQuality(int type, byte[] credential, int requestedQuality) {
final int quality;
if (type == CREDENTIAL_TYPE_PASSWORD) {
int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
@@ -1005,7 +1060,7 @@ public class LockPatternUtils {
* true
*/
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
- String managedUserPassword) {
+ byte[] managedUserPassword) {
if (!isManagedProfile(userHandle)) {
return;
}
@@ -1069,15 +1124,28 @@ public class LockPatternUtils {
* Deserialize a pattern.
* @param string The pattern serialized with {@link #patternToString}
* @return The pattern.
+ * @deprecated Pass patterns as byte[] and use byteArrayToPattern
*/
+ @Deprecated
public static List<LockPatternView.Cell> stringToPattern(String string) {
if (string == null) {
return null;
}
+ return byteArrayToPattern(string.getBytes());
+ }
+
+ /**
+ * Deserialize a pattern.
+ * @param bytes The pattern serialized with {@link #patternToByteArray}
+ * @return The pattern.
+ */
+ public static List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
+ if (bytes == null) {
+ return null;
+ }
List<LockPatternView.Cell> result = Lists.newArrayList();
- final byte[] bytes = string.getBytes();
for (int i = 0; i < bytes.length; i++) {
byte b = (byte) (bytes[i] - '1');
result.add(LockPatternView.Cell.of(b / 3, b % 3));
@@ -1089,10 +1157,22 @@ public class LockPatternUtils {
* Serialize a pattern.
* @param pattern The pattern.
* @return The pattern in string form.
+ * @deprecated Use patternToByteArray instead.
*/
+ @Deprecated
public static String patternToString(List<LockPatternView.Cell> pattern) {
+ return new String(patternToByteArray(pattern));
+ }
+
+
+ /**
+ * Serialize a pattern.
+ * @param pattern The pattern.
+ * @return The pattern in byte array form.
+ */
+ public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {
if (pattern == null) {
- return "";
+ return new byte[0];
}
final int patternSize = pattern.size();
@@ -1101,21 +1181,24 @@ public class LockPatternUtils {
LockPatternView.Cell cell = pattern.get(i);
res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
}
- return new String(res);
+ return res;
}
- public static String patternStringToBaseZero(String pattern) {
- if (pattern == null) {
- return "";
+ /**
+ * Transform a pattern byte array to base zero form.
+ * @param bytes pattern byte array.
+ * @return The pattern in base zero form.
+ */
+ public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
+ if (bytes == null) {
+ return new byte[0];
}
- final int patternSize = pattern.length();
-
+ final int patternSize = bytes.length;
byte[] res = new byte[patternSize];
- final byte[] bytes = pattern.getBytes();
for (int i = 0; i < patternSize; i++) {
res[i] = (byte) (bytes[i] - '1');
}
- return new String(res);
+ return res;
}
/*
@@ -1169,13 +1252,18 @@ public class LockPatternUtils {
*
* @return the hash of the pattern in a byte array.
*/
- public String legacyPasswordToHash(String password, int userId) {
- if (password == null) {
+ public String legacyPasswordToHash(byte[] password, int userId) {
+ if (password == null || password.length == 0) {
return null;
}
try {
- byte[] saltedPassword = (password + getSalt(userId)).getBytes();
+ // Previously the password was passed as a String with the following code:
+ // byte[] saltedPassword = (password + getSalt(userId)).getBytes();
+ // The code below creates the identical digest preimage using byte arrays:
+ byte[] salt = getSalt(userId).getBytes();
+ byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
@@ -1184,6 +1272,7 @@ public class LockPatternUtils {
System.arraycopy(md5, 0, combined, sha1.length, md5.length);
final char[] hexEncoded = HexEncoding.encode(combined);
+ Arrays.fill(saltedPassword, (byte) 0);
return new String(hexEncoded);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError("Missing digest algorithm: ", e);
@@ -1193,14 +1282,19 @@ public class LockPatternUtils {
/**
* Hash the password for password history check purpose.
*/
- private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
- if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
+ private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
+ if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
return null;
}
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
sha256.update(hashFactor);
- sha256.update((passwordToHash + getSalt(userId)).getBytes());
+ byte[] salt = getSalt(userId).getBytes();
+ byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
+ + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
+ sha256.update(saltedPassword);
+ Arrays.fill(saltedPassword, (byte) 0);
return new String(HexEncoding.encode(sha256.digest()));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError("Missing digest algorithm: ", e);
@@ -1633,7 +1727,7 @@ public class LockPatternUtils {
* @param userId The user who's lock credential to be changed
* @return {@code true} if the operation is successful.
*/
- public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
+ public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality,
long tokenHandle, byte[] token, int userId) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -1641,13 +1735,13 @@ public class LockPatternUtils {
}
LockSettingsInternal localService = getLockSettingsInternal();
if (type != CREDENTIAL_TYPE_NONE) {
- if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
+ if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must not be null and at least "
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
}
final int quality = computePasswordQuality(type, credential, requestedQuality);
- if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
- token, quality, userId)) {
+ if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token,
+ quality, userId)) {
return false;
}
setKeyguardStoredPasswordQuality(quality, userId);
@@ -1656,11 +1750,11 @@ public class LockPatternUtils {
updatePasswordHistory(credential, userId);
onAfterChangingPassword(userId);
} else {
- if (!TextUtils.isEmpty(credential)) {
+ if (!(credential == null || credential.length == 0)) {
throw new IllegalArgumentException("password must be emtpy for NONE type");
}
- if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
- tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
+ if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle,
+ token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
return false;
}
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
@@ -1891,4 +1985,22 @@ public class LockPatternUtils {
return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
}
+
+ /**
+ * Converts a CharSequence to a byte array without requiring a toString(), which creates an
+ * additional copy.
+ *
+ * @param chars The CharSequence to convert
+ * @return A byte array representing the input
+ */
+ public static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 25a5a0734bf5..4b269901ccf6 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1273,8 +1273,10 @@ public class LockPatternView extends View {
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
+ byte[] patternBytes = LockPatternUtils.patternToByteArray(mPattern);
+ String patternString = patternBytes != null ? new String(patternBytes) : null;
return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
+ patternString,
mPatternDisplayMode.ordinal(),
mInputEnabled, mInStealthMode, mEnableHapticFeedback);
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 9de9ef7f2aea..90397dffe5f9 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -49,7 +49,11 @@ public abstract class LockSettingsInternal {
*/
public abstract boolean isEscrowTokenActive(long handle, int userId);
- public abstract boolean setLockCredentialWithToken(String credential, int type,
+ /**
+ * Set the lock credential.
+ * @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 unlockUserWithToken(long tokenHandle, byte[] token, int userId);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0938e569ad7e..16517bf87afe 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -244,6 +244,11 @@ static const char* kGenerationalCCRuntimeOption = "-Xgc:generational_cc";
// Copying (CC) garbage collector.
static const char* kNoGenerationalCCRuntimeOption = "-Xgc:nogenerational_cc";
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Flag to pass to the runtime when using the apex image.
+static const char* kApexImageOption = "-Ximage:/system/framework/apex.art";
+
static AndroidRuntime* gCurRuntime = NULL;
/*
@@ -678,8 +683,17 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];
- if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
- ALOGI("Boot image: '%s'\n", bootImageBuf);
+ std::string use_apex_image =
+ server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+ ENABLE_APEX_IMAGE,
+ /*default_value=*/ "");
+ if (use_apex_image == "true") {
+ addOption(kApexImageOption);
+ ALOGI("Using Apex boot image: '%s'\n", kApexImageOption);
+ } else if (parseRuntimeOption("dalvik.vm.boot-image", bootImageBuf, "-Ximage:")) {
+ ALOGI("Using dalvik.vm.boot-image: '%s'\n", bootImageBuf);
+ } else {
+ ALOGI("Using default boot image");
}
bool checkJni = false;
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 8a280343e731..c7805ea12f02 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -221,12 +221,23 @@ void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognitio
jobject jAudioFormat = NULL;
if (event->trigger_in_data || event->capture_available) {
+ jint channelMask = (jint)audio_channel_mask_get_bits(event->audio_config.channel_mask);
+ jint channelIndexMask = (jint)AUDIO_CHANNEL_NONE;
+
+ switch (audio_channel_mask_get_representation(event->audio_config.channel_mask)) {
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ channelIndexMask = channelMask;
+ channelMask = (jint)AUDIO_CHANNEL_NONE;
+ break;
+ default:
+ break;
+ }
jAudioFormat = env->NewObject(gAudioFormatClass,
gAudioFormatCstor,
audioFormatFromNative(event->audio_config.format),
event->audio_config.sample_rate,
- inChannelMaskFromNative(event->audio_config.channel_mask),
- (jint)0 /* channelIndexMask */);
+ channelMask,
+ channelIndexMask);
}
if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp
index a18e80a4e6e1..d7d31e59ad30 100644
--- a/core/jni/android_media_AudioProductStrategies.cpp
+++ b/core/jni/android_media_AudioProductStrategies.cpp
@@ -194,12 +194,34 @@ exit:
return jStatus;
}
+static jint
+android_media_AudioSystem_getProductStrategyFromAudioAttributes(JNIEnv *env, jobject clazz,
+ jobject jAudioAttributes)
+{
+ JNIAudioAttributeHelper::UniqueAaPtr attributes = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env,
+ jAudioAttributes,
+ attributes.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ product_strategy_t psId;
+ status_t status = AudioSystem::getProductStrategyFromAudioAttributes(
+ AudioAttributes(*attributes.get()), psId);
+ if (status != NO_ERROR) {
+ return nativeToJavaStatus(status);
+ }
+ return psId;
+}
+
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
{"native_list_audio_product_strategies", "(Ljava/util/ArrayList;)I",
(void *)android_media_AudioSystem_listAudioProductStrategies},
+ {"native_get_product_strategies_from_audio_attributes", "(Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_getProductStrategyFromAudioAttributes},
};
int register_android_media_AudioProductStrategies(JNIEnv *env)
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index a1f2377041e8..1163b860977d 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -33,14 +33,16 @@
#include <unistd.h>
#include <sys/ioctl.h>
+#include <android-base/cmsg.h>
+#include <android-base/macros.h>
#include <cutils/sockets.h>
#include <netinet/tcp.h>
#include <nativehelper/ScopedUtfChars.h>
-namespace android {
+using android::base::ReceiveFileDescriptorVector;
+using android::base::SendFileDescriptorVector;
-template <typename T>
-void UNUSED(T t) {}
+namespace android {
static jfieldID field_inboundFileDescriptors;
static jfieldID field_outboundFileDescriptors;
@@ -118,67 +120,6 @@ socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor,
}
/**
- * Processes ancillary data, handling only
- * SCM_RIGHTS. Creates appropriate objects and sets appropriate
- * fields in the LocalSocketImpl object. Returns 0 on success
- * or -1 if an exception was thrown.
- */
-static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg)
-{
- struct cmsghdr *cmsgptr;
-
- for (cmsgptr = CMSG_FIRSTHDR(pMsg);
- cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) {
-
- if (cmsgptr->cmsg_level != SOL_SOCKET) {
- continue;
- }
-
- if (cmsgptr->cmsg_type == SCM_RIGHTS) {
- int *pDescriptors = (int *)CMSG_DATA(cmsgptr);
- jobjectArray fdArray;
- int count
- = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int));
-
- if (count < 0) {
- jniThrowException(env, "java/io/IOException",
- "invalid cmsg length");
- return -1;
- }
-
- fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL);
-
- if (fdArray == NULL) {
- return -1;
- }
-
- for (int i = 0; i < count; i++) {
- jobject fdObject
- = jniCreateFileDescriptor(env, pDescriptors[i]);
-
- if (env->ExceptionCheck()) {
- return -1;
- }
-
- env->SetObjectArrayElement(fdArray, i, fdObject);
-
- if (env->ExceptionCheck()) {
- return -1;
- }
- }
-
- env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
-
- if (env->ExceptionCheck()) {
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-/**
* Reads data from a socket into buf, processing any ancillary data
* and adding it to thisJ.
*
@@ -189,47 +130,48 @@ static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
void *buffer, size_t len)
{
ssize_t ret;
- struct msghdr msg;
- struct iovec iv;
- unsigned char *buf = (unsigned char *)buffer;
- // Enough buffer for a pile of fd's. We throw an exception if
- // this buffer is too small.
- struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100];
-
- memset(&msg, 0, sizeof(msg));
- memset(&iv, 0, sizeof(iv));
-
- iv.iov_base = buf;
- iv.iov_len = len;
+ std::vector<android::base::unique_fd> received_fds;
- msg.msg_iov = &iv;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsgbuf;
- msg.msg_controllen = sizeof(cmsgbuf);
-
- ret = TEMP_FAILURE_RETRY(recvmsg(fd, &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC));
-
- if (ret < 0 && errno == EPIPE) {
- // Treat this as an end of stream
- return 0;
- }
+ ret = ReceiveFileDescriptorVector(fd, buffer, len, 64, &received_fds);
if (ret < 0) {
+ if (errno == EPIPE) {
+ // Treat this as an end of stream
+ return 0;
+ }
+
jniThrowIOException(env, errno);
return -1;
}
- if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) {
- // To us, any of the above flags are a fatal error
+ if (received_fds.size() > 0) {
+ jobjectArray fdArray = env->NewObjectArray(received_fds.size(), class_FileDescriptor, NULL);
+
+ if (fdArray == NULL) {
+ // NewObjectArray has thrown.
+ return -1;
+ }
- jniThrowException(env, "java/io/IOException",
- "Unexpected error or truncation during recvmsg()");
+ for (size_t i = 0; i < received_fds.size(); i++) {
+ jobject fdObject = jniCreateFileDescriptor(env, received_fds[i].get());
- return -1;
- }
+ if (env->ExceptionCheck()) {
+ return -1;
+ }
+
+ env->SetObjectArrayElement(fdArray, i, fdObject);
+
+ if (env->ExceptionCheck()) {
+ return -1;
+ }
+ }
- if (ret >= 0) {
- socket_process_cmsg(env, thisJ, &msg);
+ for (auto &fd : received_fds) {
+ // The fds are stored in java.io.FileDescriptors now.
+ static_cast<void>(fd.release());
+ }
+
+ env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
}
return ret;
@@ -243,7 +185,6 @@ static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd,
static int socket_write_all(JNIEnv *env, jobject object, int fd,
void *buf, size_t len)
{
- ssize_t ret;
struct msghdr msg;
unsigned char *buffer = (unsigned char *)buf;
memset(&msg, 0, sizeof(msg));
@@ -256,14 +197,11 @@ static int socket_write_all(JNIEnv *env, jobject object, int fd,
return -1;
}
- struct cmsghdr *cmsg;
int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds);
- int fds[countFds];
- char msgbuf[CMSG_SPACE(countFds)];
+ std::vector<int> fds;
// Add any pending outbound file descriptors to the message
if (outboundFds != NULL) {
-
if (env->ExceptionCheck()) {
return -1;
}
@@ -274,47 +212,25 @@ static int socket_write_all(JNIEnv *env, jobject object, int fd,
return -1;
}
- fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
+ fds.push_back(jniGetFDFromFileDescriptor(env, fdObject));
if (env->ExceptionCheck()) {
return -1;
}
}
-
- // See "man cmsg" really
- msg.msg_control = msgbuf;
- msg.msg_controllen = sizeof msgbuf;
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof fds);
- memcpy(CMSG_DATA(cmsg), fds, sizeof fds);
}
- // We only write our msg_control during the first write
- while (len > 0) {
- struct iovec iv;
- memset(&iv, 0, sizeof(iv));
-
- iv.iov_base = buffer;
- iv.iov_len = len;
-
- msg.msg_iov = &iv;
- msg.msg_iovlen = 1;
-
- do {
- ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
- } while (ret < 0 && errno == EINTR);
+ ssize_t rc = SendFileDescriptorVector(fd, buffer, len, fds);
- if (ret < 0) {
+ while (rc != len) {
+ if (rc == -1) {
jniThrowIOException(env, errno);
return -1;
}
- buffer += ret;
- len -= ret;
+ buffer += rc;
+ len -= rc;
- // Wipes out any msg_control too
- memset(&msg, 0, sizeof(msg));
+ rc = send(fd, buffer, len, MSG_NOSIGNAL);
}
return 0;
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 13b059830eb9..de5e3a52a0c1 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -237,7 +237,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -335,7 +335,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -455,7 +455,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -511,7 +511,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -806,7 +806,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -1161,7 +1161,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -1207,7 +1207,7 @@ android_eglCopyBuffers
(JNIEnv *_env, jobject _this, jobject dpy, jobject surface, jint target) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"eglCopyBuffers");
- return (EGLBoolean) 0;
+ return JNI_FALSE;
}
static const char *classPathName = "android/opengl/EGL14";
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index 563f5db011e7..99bdce274f3e 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+// This source file is automatically generated
+
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
@@ -90,7 +92,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass)
egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
-
eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
@@ -103,7 +104,6 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass)
jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
-
jclass eglClass = _env->FindClass("android/opengl/EGL15");
jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
_env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
@@ -187,7 +187,7 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
static void *
fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
- if (obj == NULL){
+ if (obj == NULL) {
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
return nullptr;
@@ -198,10 +198,9 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
}
static jobject
-toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
- if (cls == eglimageClass &&
- (EGLImage)handle == EGL_NO_IMAGE) {
- return eglNoImageObject;
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
+ if (cls == eglimageClass && (EGLImage)handle == EGL_NO_IMAGE) {
+ return eglNoImageObject;
}
return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
@@ -333,7 +332,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
- return false;
+ return JNI_FALSE;
}
return (jboolean)_returnValue;
}
@@ -457,12 +456,9 @@ exit:
static jobject
android_eglCreatePlatformPixmapSurface
(JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) {
- if ((true)) {
- jniThrowException(_env, "java/lang/UnsupportedOperationException",
- "eglCreatePlatformPixmapSurface");
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
+ "eglCreatePlatformPixmapSurface");
return nullptr;
- }
- return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
}
/* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 1eb110135bf5..fef8116dc93a 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -102,6 +102,7 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
if (obj == NULL){
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
+ return nullptr;
}
return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index ee82fc71ce8d..a5dcbf765b60 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -529,6 +529,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -598,6 +599,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index ff4536ee17de..0e20d474e275 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -2682,6 +2682,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -3907,6 +3908,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 9aca86672fb9..992239865db7 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -3010,6 +3010,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -3979,6 +3980,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 4c51e2dc5f37..27dbd399d77c 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -706,6 +706,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -917,6 +918,7 @@ exit:
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 191472d086f6..8d702d11d8fe 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -41,6 +41,7 @@ static struct {
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
+ jmethodID dispatchConfigChanged;
} gDisplayEventReceiverClassInfo;
@@ -61,6 +62,8 @@ private:
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) override;
};
@@ -114,6 +117,23 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
+void NativeDisplayEventReceiver::dispatchConfigChanged(nsecs_t timestamp,
+ PhysicalDisplayId displayId,
+ int32_t configId) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking config changed handler.", this);
+ env->CallVoidMethod(receiverObj.get(),
+ gDisplayEventReceiverClassInfo.dispatchConfigChanged,
+ timestamp, displayId, configId);
+ ALOGV("receiver %p ~ Returned from config changed handler.", this);
+ }
+
+ mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+}
+
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj, jint vsyncSource) {
@@ -180,6 +200,8 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
+ gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
+ gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
return res;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 4069e95d8c35..4c25fd465301 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -698,6 +698,25 @@ static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
return configArray;
}
+static jboolean nativeSetAllowedDisplayConfigs(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jintArray configArray) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == nullptr) return JNI_FALSE;
+
+ std::vector<int32_t> allowedConfigs;
+ jsize configArraySize = env->GetArrayLength(configArray);
+ allowedConfigs.reserve(configArraySize);
+
+ jint* configArrayElements = env->GetIntArrayElements(configArray, 0);
+ for (int i = 0; i < configArraySize; i++) {
+ allowedConfigs.push_back(configArrayElements[i]);
+ }
+ env->ReleaseIntArrayElements(configArray, configArrayElements, 0);
+
+ size_t result = SurfaceComposerClient::setAllowedDisplayConfigs(token, allowedConfigs);
+ return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
@@ -1194,6 +1213,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetActiveConfig },
{"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveConfig },
+ {"nativeSetAllowedDisplayConfigs", "(Landroid/os/IBinder;[I)Z",
+ (void*)nativeSetAllowedDisplayConfigs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 73e67896443c..2ccb01adfd3e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -155,10 +155,10 @@ static std::atomic_uint32_t gBlastulaPoolCount = 0;
static int gBlastulaPoolEventFD = -1;
/**
- * The maximum value that the gBlastulaPoolMax variable may take. This value
- * is a mirror of Zygote.BLASTULA_POOL_MAX_LIMIT
+ * The maximum value that the gBlastulaPoolSizeMax variable may take. This value
+ * is a mirror of ZygoteServer.BLASTULA_POOL_SIZE_MAX_LIMIT
*/
-static constexpr int BLASTULA_POOL_MAX_LIMIT = 10;
+static constexpr int BLASTULA_POOL_SIZE_MAX_LIMIT = 100;
/**
* A helper class containing accounting information for Blastulas.
@@ -216,6 +216,19 @@ class BlastulaTableEntry {
}
}
+ void Clear() {
+ EntryStorage storage = mStorage.load();
+
+ if (storage != INVALID_ENTRY_VALUE) {
+ close(storage.read_pipe_fd);
+ mStorage.store(INVALID_ENTRY_VALUE);
+ }
+ }
+
+ void Invalidate() {
+ mStorage.store(INVALID_ENTRY_VALUE);
+ }
+
/**
* @return A copy of the data stored in this entry.
*/
@@ -257,7 +270,7 @@ class BlastulaTableEntry {
* the BlastulaTableEntry class prevent data races during these concurrent
* operations.
*/
-static std::array<BlastulaTableEntry, BLASTULA_POOL_MAX_LIMIT> gBlastulaTable;
+static std::array<BlastulaTableEntry, BLASTULA_POOL_SIZE_MAX_LIMIT> gBlastulaTable;
/**
* The list of open zygote file descriptors.
@@ -736,10 +749,19 @@ static void CreatePkgSandboxSource(const std::string& sandbox_source, fail_fn_t
}
static void PreparePkgSpecificDirs(const std::vector<std::string>& package_names,
- const std::vector<std::string>& volume_labels,
bool mount_all_obbs, const std::string& sandbox_id,
userid_t user_id, uid_t uid, fail_fn_t fail_fn) {
- for (auto& label : volume_labels) {
+ std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir("/storage"), closedir);
+ if (!dirp) {
+ fail_fn(CREATE_ERROR("Failed to opendir /storage: %s", strerror(errno)));
+ }
+ struct dirent* ent;
+ while ((ent = readdir(dirp.get()))) {
+ if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "self")) {
+ continue;
+ }
+ std::string label(ent->d_name);
+
std::string mnt_source = StringPrintf("/mnt/runtime/write/%s", label.c_str());
std::string mnt_target = StringPrintf("/storage/%s", label.c_str());
if (label == "emulated") {
@@ -819,7 +841,7 @@ static void HandleMountModeInstaller(int mount_mode,
static void MountEmulatedStorage(uid_t uid, jint mount_mode,
bool force_mount_namespace, const std::string& package_name,
const std::vector<std::string>& packages_for_uid,
- const std::vector<std::string>& visible_vol_ids, const std::string& sandbox_id,
+ const std::string& sandbox_id,
fail_fn_t fail_fn) {
// See storage config details at http://source.android.com/tech/storage/
@@ -878,16 +900,16 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
userid_t user_id = multiuser_get_user_id(uid);
CreatePkgSandboxTarget(user_id, fail_fn);
- std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package", user_id);
- if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",
+ std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d/package", user_id);
+ if (TEMP_FAILURE_RETRY(mount(pkg_sandbox_dir.c_str(), "/storage",
nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
- pkgSandboxDir.c_str(), strerror(errno)));
+ pkg_sandbox_dir.c_str(), strerror(errno)));
}
HandleMountModeInstaller(mount_mode, user_id, sandbox_id, fail_fn);
- PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
+ PreparePkgSpecificDirs(packages_for_uid,
mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn);
}
} else {
@@ -900,16 +922,16 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
// Mount user-specific symlink helper into place
userid_t user_id = multiuser_get_user_id(uid);
- const String8 userSource(String8::format("/mnt/user/%d", user_id));
- if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+ const String8 user_source(String8::format("/mnt/user/%d", user_id));
+ if (fs_prepare_dir(user_source.string(), 0751, 0, 0) == -1) {
fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s",
- userSource.string()));
+ user_source.string()));
}
- if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+ if (TEMP_FAILURE_RETRY(mount(user_source.string(), "/storage/self",
nullptr, MS_BIND, nullptr)) == -1) {
fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
- userSource.string(), strerror(errno)));
+ user_source.string(), strerror(errno)));
}
}
}
@@ -1159,6 +1181,14 @@ static void UnblockSignal(int signum, fail_fn_t fail_fn) {
}
}
+static void ClearBlastulaTable() {
+ for (BlastulaTableEntry& entry : gBlastulaTable) {
+ entry.Clear();
+ }
+
+ gBlastulaPoolCount = 0;
+}
+
// Utility routine to fork a process from the zygote.
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
@@ -1201,12 +1231,17 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fds_to_close, fail_fn);
+ // Invalidate the entries in the blastula table.
+ ClearBlastulaTable();
+
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
gOpenFdTable->ReopenOrDetach(fail_fn);
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
+ } else {
+ ALOGD("Forked child process %d", pid);
}
// We blocked SIGCHLD prior to a fork, we unblock it here.
@@ -1224,7 +1259,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
bool is_child_zygote, jstring managed_instruction_set,
jstring managed_app_data_dir, jstring managed_package_name,
jobjectArray managed_pacakges_for_uid,
- jobjectArray managed_visible_vol_ids, jstring managed_sandbox_id) {
+ jstring managed_sandbox_id) {
const char* process_name = is_system_server ? "system_server" : "zygote";
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1272,12 +1307,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
ExtractJStringArray(env, process_name, managed_nice_name, managed_pacakges_for_uid).
value_or(std::vector<std::string>());
- std::vector<std::string> visible_vol_ids =
- ExtractJStringArray(env, process_name, managed_nice_name, managed_visible_vol_ids).
- value_or(std::vector<std::string>());
-
MountEmulatedStorage(uid, mount_external, use_native_bridge, package_name.value(),
- packages_for_uid, visible_vol_ids, sandbox_id.value_or(""), fail_fn);
+ packages_for_uid, sandbox_id.value_or(""), fail_fn);
// If this zygote isn't root, it won't be able to create a process group,
// since the directory is owned by root.
@@ -1580,7 +1611,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
jint mount_external, jstring se_info, jstring nice_name,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
jstring instruction_set, jstring app_data_dir, jstring package_name,
- jobjectArray packages_for_uid, jobjectArray visible_vol_ids, jstring sandbox_id) {
+ jobjectArray packages_for_uid, jstring sandbox_id) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -1612,7 +1643,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
capabilities, capabilities,
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- package_name, packages_for_uid, visible_vol_ids, sandbox_id);
+ package_name, packages_for_uid, sandbox_id);
}
return pid;
}
@@ -1638,7 +1669,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
- false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ false, nullptr, nullptr, nullptr, nullptr, nullptr);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -1792,7 +1823,7 @@ static void com_android_internal_os_Zygote_nativeSpecializeBlastula(
jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring nice_name,
jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir,
- jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids,
+ jstring package_name, jobjectArray packages_for_uid,
jstring sandbox_id) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
@@ -1800,7 +1831,7 @@ static void com_android_internal_os_Zygote_nativeSpecializeBlastula(
capabilities, capabilities,
mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- package_name, packages_for_uid, visible_vol_ids, sandbox_id);
+ package_name, packages_for_uid, sandbox_id);
}
/**
@@ -1887,11 +1918,32 @@ static jint com_android_internal_os_Zygote_nativeGetBlastulaPoolCount(JNIEnv* en
return gBlastulaPoolCount;
}
+/**
+ * Kills all processes currently in the blastula pool.
+ *
+ * @param env Managed runtime environment
+ * @return The number of blastulas currently in the blastula pool
+ */
+static void com_android_internal_os_Zygote_nativeEmptyBlastulaPool(JNIEnv* env, jclass) {
+ for (auto& entry : gBlastulaTable) {
+ auto entry_storage = entry.GetValues();
+
+ if (entry_storage.has_value()) {
+ kill(entry_storage.value().pid, SIGKILL);
+ close(entry_storage.value().read_pipe_fd);
+
+ // Avoid a second atomic load by invalidating instead of clearing.
+ entry.Invalidate();
+ --gBlastulaPoolCount;
+ }
+ }
+}
+
static const JNINativeMethod gMethods[] = {
{ "nativeSecurityInit", "()V",
(void *) com_android_internal_os_Zygote_nativeSecurityInit },
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -1906,7 +1958,7 @@ static const JNINativeMethod gMethods[] = {
{ "nativeForkBlastula", "(II[I)I",
(void *) com_android_internal_os_Zygote_nativeForkBlastula },
{ "nativeSpecializeBlastula",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V",
(void *) com_android_internal_os_Zygote_nativeSpecializeBlastula },
{ "nativeGetSocketFDs", "(Z)V",
(void *) com_android_internal_os_Zygote_nativeGetSocketFDs },
@@ -1917,7 +1969,9 @@ static const JNINativeMethod gMethods[] = {
{ "nativeGetBlastulaPoolEventFD", "()I",
(void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolEventFD },
{ "nativeGetBlastulaPoolCount", "()I",
- (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolCount }
+ (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolCount },
+ { "nativeEmptyBlastulaPool", "()V",
+ (void *) com_android_internal_os_Zygote_nativeEmptyBlastulaPool }
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index ee14a89b54ef..c806162c2534 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -4237,6 +4237,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -4306,6 +4307,7 @@ exit:
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return (jint)0;
}
return (jint)_returnValue;
}
@@ -4902,6 +4904,7 @@ android_glGetBufferParameteriv__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetBufferParameteriv");
+ return;
}
/* void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
@@ -4910,6 +4913,7 @@ android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetBufferParameteriv");
+ return;
}
/* void glGetClipPlanef ( GLenum pname, GLfloat *eqn ) */
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index f74fc2129740..efbe8bacb58f 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -615,6 +615,40 @@ enum Action {
// CATEGORY: SETTINGS
// OS: Q
ACTION_PANEL_INTERACTION = 1658;
+
+ // ACTION: Show Contextual homepage, log latency in loading cards
+ ACTION_CONTEXTUAL_HOME_SHOW = 1662;
+
+ // ACTION: Contextual card displays
+ ACTION_CONTEXTUAL_CARD_SHOW = 1663;
+
+ // ACTION: Contextual cards are eligible to be shown, but don't rank high
+ ACTION_CONTEXTUAL_CARD_NOT_SHOW = 1664;
+
+ // ACTION: Settings > long press a card, and click dismiss
+ // Contextual card is dismissed
+ ACTION_CONTEXTUAL_CARD_DISMISS = 1665;
+
+ // ACTION: Settings > click a card
+ // Contextual card is clicked
+ ACTION_CONTEXTUAL_CARD_CLICK = 1666;
+
+ // Mapping: go/at-mapping
+ ACTION_ATSG = 1674;
+
+ ACTION_ATPG = 1675;
+
+ ACTION_ATCLPB = 1676;
+
+ ACTION_ATCGIB = 1677;
+
+ ACTION_ATCPAB = 1678;
+
+ ACTION_ATCSAUC = 1679;
+
+ ACTION_ATCSCUC = 1680;
+
+ ACTION_ATCHNUC = 1681;
}
/**
@@ -2235,4 +2269,19 @@ enum PageId {
// Panel for Media Output
PANEL_MEDIA_OUTPUT = 1657;
+
+ // Mapping: go/at-mapping
+ PAGE_ATSSI = 1667;
+
+ PAGE_ATSII = 1668;
+
+ PAGE_ATUS = 1669;
+
+ PAGE_ATSSP = 1670;
+
+ PAGE_ATSAP = 1671;
+
+ PAGE_ATSCP = 1672;
+
+ PAGE_ATHNP = 1673;
}
diff --git a/core/res/res/drawable/ic_action_open.xml b/core/res/res/drawable/ic_action_open.xml
index 3d3d36ece0af..ba0a38d6c104 100644
--- a/core/res/res/drawable/ic_action_open.xml
+++ b/core/res/res/drawable/ic_action_open.xml
@@ -17,8 +17,10 @@ Copyright (C) 2019 The Android Open Source Project
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?attr/colorControlNormal">
+ >
<path
- android:fillColor="#FF737373"
+ android:fillColor="@color/white"
android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_qs_battery_saver.xml b/core/res/res/drawable/ic_qs_battery_saver.xml
index 89b25690a5db..93975b61948e 100644
--- a/core/res/res/drawable/ic_qs_battery_saver.xml
+++ b/core/res/res/drawable/ic_qs_battery_saver.xml
@@ -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.
@@ -21,8 +21,10 @@
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
- android:pathData="M5,3
- l3.5,0 l0,-1.5 l7,0 l0,1.5 l3.5,0 l0,19.5 l-14,0z
- M10.5,8.5 l0,3 l-3,0 l0,3 l3,0 l0,3 l3,0 l0,-3 l3,0 l0,-3 l-3,0 l0,-3 z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#FFF"
+ android:pathData="M16.67,4H14.5V2h-5v2H7.33C6.6,4 6,4.6 6,5.33V15v5.67C6,21.4 6.6,22 7.33,22h9.33C17.4,22 18,21.4 18,20.67V15V5.33C18,4.6 17.4,4 16.67,4zM16,15v5H8v-5V6h8V15z"/>
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M15,12l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z"/>
+
</vector>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 733878b9882b..8f2d6c3e02f4 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -185,4 +185,20 @@
<item>@string/app_info</item>
</string-array>
+ <!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
+ e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
+ eUICC, then the value of this array should be:
+ <integer-array name="non_removable_euicc_slots">
+ <item>1</item>
+ </integer-array>
+ If a device has three physical slots and slot 1 and 2 are eUICCs, then the value of
+ this array should be:
+ <integer-array name="non_removable_euicc_slots">
+ <item>1</item>
+ <item>2</item>
+ </integer-array>
+ This is used to differentiate between removable eUICCs and built in eUICCs, and should
+ be set by OEMs for devices which use eUICCs. -->
+ <integer-array name="non_removable_euicc_slots"></integer-array>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 489ceb72ad60..910af4c63630 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2008,11 +2008,6 @@
a transaction, so it interacts poorly with SECURE_DELETE. -->
<string name="db_default_journal_mode" translatable="false">TRUNCATE</string>
- <!-- Enables compatibility WAL mode.
- In this mode, only database journal mode will be changed, connection pool
- size will still be limited to a single connection. -->
- <bool name="db_compatibility_wal_supported">true</bool>
-
<!-- Maximum size of the persistent journal file in bytes.
If the journal file grows to be larger than this amount then SQLite will
truncate it after committing the transaction. -->
@@ -2272,6 +2267,7 @@
<!-- If the sensor that wakes up the lock screen is available or not. -->
<bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
+ <integer name="config_dozeWakeLockScreenDebounce">3000</integer>
<!-- Control whether the always on display mode is available. This should only be enabled on
devices where the display has been tuned to be power efficient in DOZE and/or DOZE_SUSPEND
@@ -3934,4 +3930,25 @@
The same restrictions apply to this array. -->
<array name="config_displayWhiteBalanceDisplayColorTemperatures">
</array>
+
+ <!-- All of the paths defined for the batterymeter are defined on a 12x20 canvas, and must
+ be parsable by android.utill.PathParser -->
+ <string name="config_batterymeterPerimeterPath" translatable="false">
+ M3.5,2 v0 H1.33 C0.6,2 0,2.6 0,3.33 V13v5.67 C0,19.4 0.6,20 1.33,20 h9.33 C11.4,20 12,19.4 12,18.67 V13V3.33 C12,2.6 11.4,2 10.67,2 H8.5 V0 H3.5 z M2,18v-7V4h8v9v5H2L2,18z
+ </string>
+
+ <string name="config_batterymeterFillMask" translatable="false">
+ M2,18 v-14 h8 v14 z
+ </string>
+ <string name="config_batterymeterBoltPath" translatable="false">
+ M5,17.5 V12 H3 L7,4.5 V10 h2 L5,17.5 z
+ </string>
+ <string name="config_batterymeterPowersavePath" translatable="false">
+ M9,10l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z
+ </string>
+
+ <!-- A dual tone battery meter draws the perimeter path twice - once to define the shape
+ and a second time clipped to the fill level to indicate charge -->
+ <bool name="config_batterymeterDualTone">false</bool>
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dbdc763739b2..4e47b1fb6b2a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -779,7 +779,7 @@
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to make and manage phone calls?</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgrouplab_sensors">Body Sensors</string>
+ <string name="permgrouplab_sensors">Body sensors</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_sensors">access sensor data about your vital signs</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
@@ -795,12 +795,12 @@
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your music?</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgrouplab_visual">Photos &amp; Videos</string>
+ <string name="permgrouplab_visual">Photos &amp; videos</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_visual">access your photos &amp; videos</string>
<!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
<string name="permgrouprequest_visual">Allow
- &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos &amp; videos?</string>
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos, including tagged locations?</string>
<!-- Title for the capability of an accessibility service to retrieve window content. -->
<string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1f73dda18c7b..426d813885fe 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -752,7 +752,6 @@
<java-symbol type="string" name="date_time" />
<java-symbol type="string" name="date_time_set" />
<java-symbol type="string" name="date_time_done" />
- <java-symbol type="bool" name="db_compatibility_wal_supported" />
<java-symbol type="string" name="db_default_journal_mode" />
<java-symbol type="string" name="db_default_sync_mode" />
<java-symbol type="string" name="db_wal_sync_mode" />
@@ -2987,6 +2986,8 @@
<java-symbol type="array" name="resolver_target_actions_pin" />
<java-symbol type="array" name="resolver_target_actions_unpin" />
+ <java-symbol type="array" name="non_removable_euicc_slots" />
+
<java-symbol type="string" name="install_carrier_app_notification_title" />
<java-symbol type="string" name="install_carrier_app_notification_text" />
<java-symbol type="string" name="install_carrier_app_notification_text_app_name" />
@@ -3195,6 +3196,11 @@
<java-symbol type="raw" name="fallback_categories" />
<java-symbol type="string" name="config_icon_mask" />
+ <java-symbol type="string" name="config_batterymeterPerimeterPath" />
+ <java-symbol type="string" name="config_batterymeterFillMask" />
+ <java-symbol type="string" name="config_batterymeterBoltPath" />
+ <java-symbol type="string" name="config_batterymeterPowersavePath" />
+ <java-symbol type="bool" name="config_batterymeterDualTone" />
<!-- Accessibility Shortcut -->
<java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
@@ -3404,6 +3410,7 @@
<java-symbol type="string" name="config_dozeLongPressSensorType" />
<java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" />
+ <java-symbol type="integer" name="config_dozeWakeLockScreenDebounce" />
<java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
<java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
new file mode 100644
index 000000000000..833c7347926b
--- /dev/null
+++ b/core/tests/coretests/Android.bp
@@ -0,0 +1,113 @@
+android_test {
+ name: "FrameworksCoreTests",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/I*.aidl",
+ "DisabledTestApp/src/**/*.java",
+ "EnabledTestApp/src/**/*.java",
+ "BinderProxyCountingTestApp/src/**/*.java",
+ "BinderProxyCountingTestService/src/**/*.java",
+ "aidl/**/I*.aidl",
+ ],
+
+ aidl: {
+ local_include_dirs: ["aidl"],
+ },
+
+ dxflags: ["--core-library"],
+
+ aaptflags: [
+ "-0 .dat",
+ "-0 .gld",
+ "-c fa",
+ ],
+ static_libs: [
+ "frameworks-base-testutils",
+ "core-tests-support",
+ "android-common",
+ "frameworks-core-util-lib",
+ "mockwebserver",
+ "guava",
+ "androidx.test.espresso.core",
+ "androidx.test.ext.junit",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "ub-uiautomator",
+ "platform-test-annotations",
+ "truth-prebuilt",
+ "print-test-util-lib",
+ "testng",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "telephony-common",
+ "testables",
+ "org.apache.http.legacy",
+ "android.test.base",
+ "android.test.mock",
+ "framework-atb-backward-compatibility",
+ ],
+
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ certificate: "platform",
+
+ resource_dirs: ["res"],
+ resource_zips: [":FrameworksCoreTests_apks_as_resources"],
+}
+
+// Rules to copy all the test apks to the intermediate raw resource directory
+java_genrule {
+ name: "FrameworksCoreTests_apks_as_resources",
+ srcs: [
+ ":FrameworksCoreTests_install",
+ ":FrameworksCoreTests_install_bad_dex",
+ ":FrameworksCoreTests_install_complete_package_info",
+ ":FrameworksCoreTests_install_decl_perm",
+ ":FrameworksCoreTests_install_jni_lib_open_from_apk",
+ ":FrameworksCoreTests_install_loc_auto",
+ ":FrameworksCoreTests_install_loc_internal",
+ ":FrameworksCoreTests_install_loc_sdcard",
+ ":FrameworksCoreTests_install_loc_unspecified",
+ ":FrameworksCoreTests_install_multi_package",
+ ":FrameworksCoreTests_install_split_base",
+ ":FrameworksCoreTests_install_split_feature_a",
+ ":FrameworksCoreTests_install_use_perm_good",
+ ":FrameworksCoreTests_install_uses_feature",
+ ":FrameworksCoreTests_install_verifier_bad",
+ ":FrameworksCoreTests_install_verifier_good",
+ ":FrameworksCoreTests_keyset_permdef_sa_unone",
+ ":FrameworksCoreTests_keyset_permuse_sa_ua_ub",
+ ":FrameworksCoreTests_keyset_permuse_sb_ua_ub",
+ ":FrameworksCoreTests_keyset_sab_ua",
+ ":FrameworksCoreTests_keyset_sa_ua",
+ ":FrameworksCoreTests_keyset_sa_uab",
+ ":FrameworksCoreTests_keyset_sa_ua_ub",
+ ":FrameworksCoreTests_keyset_sa_ub",
+ ":FrameworksCoreTests_keyset_sa_unone",
+ ":FrameworksCoreTests_keyset_sau_ub",
+ ":FrameworksCoreTests_keyset_sb_ua",
+ ":FrameworksCoreTests_keyset_sb_ub",
+ ":FrameworksCoreTests_keyset_splata_api",
+ ":FrameworksCoreTests_keyset_splat_api",
+ ":FrameworksCoreTests_locales",
+ ":FrameworksCoreTests_version_1",
+ ":FrameworksCoreTests_version_1_diff",
+ ":FrameworksCoreTests_version_1_nosys",
+ ":FrameworksCoreTests_version_2",
+ ":FrameworksCoreTests_version_2_diff",
+ ":FrameworksCoreTests_version_3",
+ ],
+ out: ["FrameworkCoreTests_apks_as_resources.res.zip"],
+ tools: ["soong_zip"],
+
+ cmd: "mkdir -p $(genDir)/res/raw && " +
+ "for i in $(in); do " +
+ " x=$${i##*FrameworksCoreTests_}; echo $${x}; cp $$i $(genDir)/res/raw/$${x%.apk};" +
+ "done && " +
+ "$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+}
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
deleted file mode 100644
index 40ebd44b9bd0..000000000000
--- a/core/tests/coretests/Android.mk
+++ /dev/null
@@ -1,85 +0,0 @@
-ACTUAL_LOCAL_PATH := $(call my-dir)
-
-# this var will hold all the test apk module names later.
-FrameworkCoreTests_all_apks :=
-
-# We have to include the subdir makefiles first
-# so that FrameworkCoreTests_all_apks will be populated correctly.
-include $(call all-makefiles-under,$(ACTUAL_LOCAL_PATH))
-
-LOCAL_PATH := $(ACTUAL_LOCAL_PATH)
-
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-Iaidl-files-under, src) \
- $(call all-java-files-under, DisabledTestApp/src) \
- $(call all-java-files-under, EnabledTestApp/src) \
- $(call all-java-files-under, BinderProxyCountingTestApp/src) \
- $(call all-java-files-under, BinderProxyCountingTestService/src) \
- $(call all-Iaidl-files-under, aidl)
-
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
-LOCAL_STATIC_JAVA_LIBRARIES := \
- frameworks-base-testutils \
- core-tests-support \
- android-common \
- frameworks-core-util-lib \
- mockwebserver \
- guava \
- androidx.test.espresso.core \
- androidx.test.ext.junit \
- androidx.test.runner \
- androidx.test.rules \
- mockito-target-minus-junit4 \
- ub-uiautomator \
- platform-test-annotations \
- truth-prebuilt \
- print-test-util-lib \
- testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.runner \
- telephony-common \
- testables \
- org.apache.http.legacy \
- android.test.base \
- android.test.mock \
- framework-atb-backward-compatibility \
-
-LOCAL_PACKAGE_NAME := FrameworksCoreTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-# intermediate dir to include all the test apks as raw resource
-FrameworkCoreTests_intermediates := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/test_apks/res
-LOCAL_RESOURCE_DIR := $(FrameworkCoreTests_intermediates) $(LOCAL_PATH)/res
-
-# Disable AAPT2 because the hacks below depend on the AAPT rules implementation
-LOCAL_USE_AAPT2 := false
-
-include $(BUILD_PACKAGE)
-# Rules to copy all the test apks to the intermediate raw resource directory
-FrameworkCoreTests_all_apks_res := $(addprefix $(FrameworkCoreTests_intermediates)/raw/, \
- $(foreach a, $(FrameworkCoreTests_all_apks), $(patsubst FrameworkCoreTests_%,%,$(a))))
-
-$(FrameworkCoreTests_all_apks_res): $(FrameworkCoreTests_intermediates)/raw/%: $(call intermediates-dir-for,APPS,FrameworkCoreTests_%)/package.apk
- $(call copy-file-to-new-target)
-
-# Use R_file_stamp as dependency because we want the test apks in place before the R.java is generated.
-$(R_file_stamp) : $(FrameworkCoreTests_all_apks_res)
-
-FrameworkCoreTests_all_apks :=
-FrameworkCoreTests_intermediates :=
-FrameworkCoreTests_all_apks_res :=
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.bp b/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
new file mode 100644
index 000000000000..6279a4873c67
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "BinderProxyCountingTestApp",
+
+ static_libs: ["coretests-aidl"],
+ srcs: ["**/*.java"],
+
+ sdk_version: "current",
+ certificate: "platform",
+
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
deleted file mode 100644
index 4642694d7b67..000000000000
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.bp b/core/tests/coretests/BinderProxyCountingTestService/Android.bp
new file mode 100644
index 000000000000..22718cb86d66
--- /dev/null
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "BinderProxyCountingTestService",
+
+ static_libs: ["coretests-aidl"],
+ srcs: ["**/*.java"],
+
+ platform_apis: true,
+ certificate: "platform",
+
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
deleted file mode 100644
index f852c7afeacd..000000000000
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/core/tests/coretests/BstatsTestApp/Android.bp
new file mode 100644
index 000000000000..424c71a4d8d0
--- /dev/null
+++ b/core/tests/coretests/BstatsTestApp/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "BstatsTestApp",
+
+ test_suites: [
+ "device-tests",
+ ],
+
+ static_libs: ["coretests-aidl"],
+
+ srcs: ["**/*.java"],
+
+ sdk_version: "current",
+ certificate: "platform",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
deleted file mode 100644
index a5872a5e5be9..000000000000
--- a/core/tests/coretests/BstatsTestApp/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BstatsTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/DisabledTestApp/Android.bp b/core/tests/coretests/DisabledTestApp/Android.bp
new file mode 100644
index 000000000000..419816e42eff
--- /dev/null
+++ b/core/tests/coretests/DisabledTestApp/Android.bp
@@ -0,0 +1,8 @@
+android_test_helper_app {
+ name: "DisabledTestApp",
+
+ srcs: ["**/*.java"],
+
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/core/tests/coretests/DisabledTestApp/Android.mk b/core/tests/coretests/DisabledTestApp/Android.mk
deleted file mode 100644
index e4304f7cef73..000000000000
--- a/core/tests/coretests/DisabledTestApp/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := DisabledTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/EnabledTestApp/Android.bp b/core/tests/coretests/EnabledTestApp/Android.bp
new file mode 100644
index 000000000000..bc4f4bd2e4d7
--- /dev/null
+++ b/core/tests/coretests/EnabledTestApp/Android.bp
@@ -0,0 +1,8 @@
+android_test_helper_app {
+ name: "EnabledTestApp",
+
+ srcs: ["**/*.java"],
+
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/core/tests/coretests/EnabledTestApp/Android.mk b/core/tests/coretests/EnabledTestApp/Android.mk
deleted file mode 100644
index cd37f0883c63..000000000000
--- a/core/tests/coretests/EnabledTestApp/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := EnabledTestApp
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/aidl/Android.bp b/core/tests/coretests/aidl/Android.bp
new file mode 100644
index 000000000000..6e442db78500
--- /dev/null
+++ b/core/tests/coretests/aidl/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test {
+ name: "coretests-aidl",
+ sdk_version: "current",
+ srcs: ["**/*.aidl"],
+}
diff --git a/core/tests/coretests/aidl/Android.mk b/core/tests/coretests/aidl/Android.mk
deleted file mode 100644
index 86e36b61a5ae..000000000000
--- a/core/tests/coretests/aidl/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-subdir-Iaidl-files)
-LOCAL_MODULE := coretests-aidl
-include $(BUILD_STATIC_JAVA_LIBRARY) \ No newline at end of file
diff --git a/core/tests/coretests/apks/Android.bp b/core/tests/coretests/apks/Android.bp
new file mode 100644
index 000000000000..20c87b2d2ce9
--- /dev/null
+++ b/core/tests/coretests/apks/Android.bp
@@ -0,0 +1,7 @@
+java_defaults {
+ name: "FrameworksCoreTests_apks_defaults",
+ sdk_version: "current",
+
+ // Every package should have a native library
+ jni_libs: ["libframeworks_coretests_jni"],
+}
diff --git a/core/tests/coretests/apks/Android.mk b/core/tests/coretests/apks/Android.mk
deleted file mode 100644
index 98c0c2aee38b..000000000000
--- a/core/tests/coretests/apks/Android.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-FrameworkCoreTests_BUILD_PACKAGE := $(LOCAL_PATH)/FrameworkCoreTests_apk.mk
-
-# build sub packages
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
deleted file mode 100644
index 8a7d72a5200b..000000000000
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-
-LOCAL_MODULE_TAGS := tests
-
-# Disable dexpreopt.
-LOCAL_DEX_PREOPT := false
-
-# Make sure every package name gets the FrameworkCoreTests_ prefix.
-LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
-LOCAL_SDK_VERSION := current
-
-# Every package should have a native library
-LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
-
-FrameworkCoreTests_all_apks += $(LOCAL_PACKAGE_NAME)
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install-split-base/Android.bp b/core/tests/coretests/apks/install-split-base/Android.bp
new file mode 100644
index 000000000000..ddf75b224359
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-base/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_split_base",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install-split-base/Android.mk b/core/tests/coretests/apks/install-split-base/Android.mk
deleted file mode 100644
index 5b60e3167fc7..000000000000
--- a/core/tests/coretests/apks/install-split-base/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_split_base
-
-include $(FrameworkCoreTests_BUILD_PACKAGE) \ No newline at end of file
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.bp b/core/tests/coretests/apks/install-split-feature-a/Android.bp
new file mode 100644
index 000000000000..9ec9893cc408
--- /dev/null
+++ b/core/tests/coretests/apks/install-split-feature-a/Android.bp
@@ -0,0 +1,11 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_split_feature_a",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+
+ aaptflags: [
+ "--custom-package com.google.android.dexapis.splitapp.feature_a",
+ "--package-id 0x80",
+ ],
+}
diff --git a/core/tests/coretests/apks/install-split-feature-a/Android.mk b/core/tests/coretests/apks/install-split-feature-a/Android.mk
deleted file mode 100644
index 0f37d16a7688..000000000000
--- a/core/tests/coretests/apks/install-split-feature-a/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_split_feature_a
-
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT_FLAGS += --custom-package com.google.android.dexapis.splitapp.feature_a
-LOCAL_AAPT_FLAGS += --package-id 0x80
-
-include $(FrameworkCoreTests_BUILD_PACKAGE) \ No newline at end of file
diff --git a/core/tests/coretests/apks/install/Android.bp b/core/tests/coretests/apks/install/Android.bp
new file mode 100644
index 000000000000..e783fe2ec2dc
--- /dev/null
+++ b/core/tests/coretests/apks/install/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install/Android.mk b/core/tests/coretests/apks/install/Android.mk
deleted file mode 100644
index b38dc20a181e..000000000000
--- a/core/tests/coretests/apks/install/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.bp b/core/tests/coretests/apks/install_bad_dex/Android.bp
new file mode 100644
index 000000000000..d156793cf22a
--- /dev/null
+++ b/core/tests/coretests/apks/install_bad_dex/Android.bp
@@ -0,0 +1,23 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_bad_dex_",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["src/**/*.java"],
+}
+
+// Inject bad classes.dex file.
+java_genrule {
+ name: "FrameworksCoreTests_install_bad_dex",
+ tools: [
+ "soong_zip",
+ "merge_zips",
+ ],
+ srcs: [
+ ":FrameworksCoreTests_install_bad_dex_",
+ "classes.dex",
+ ],
+ out: ["FrameworksCoreTests_install_bad_dex.apk"],
+ cmd: "$(location soong_zip) -o $(genDir)/classes.dex.zip -j -f $(location classes.dex) && " +
+ "$(location merge_zips) -ignore-duplicates $(out) $(genDir)/classes.dex.zip " +
+ "$(location :FrameworksCoreTests_install_bad_dex_)",
+}
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.mk b/core/tests/coretests/apks/install_bad_dex/Android.mk
deleted file mode 100644
index 05983aa6ec7b..000000000000
--- a/core/tests/coretests/apks/install_bad_dex/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_bad_dex
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-# Override target specific variable PRIVATE_DEX_FILE to inject bad classes.dex file.
-$(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(LOCAL_PATH)/classes.dex
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.bp b/core/tests/coretests/apks/install_complete_package_info/Android.bp
new file mode 100644
index 000000000000..123558bda076
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/Android.bp
@@ -0,0 +1,7 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_complete_package_info",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
+
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.mk b/core/tests/coretests/apks/install_complete_package_info/Android.mk
deleted file mode 100644
index 19bf3561a706..000000000000
--- a/core/tests/coretests/apks/install_complete_package_info/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_complete_package_info
-#LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-#include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.bp b/core/tests/coretests/apks/install_decl_perm/Android.bp
new file mode 100644
index 000000000000..868e8b51bd49
--- /dev/null
+++ b/core/tests/coretests/apks/install_decl_perm/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_decl_perm",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.mk b/core/tests/coretests/apks/install_decl_perm/Android.mk
deleted file mode 100644
index 86370c8017a5..000000000000
--- a/core/tests/coretests/apks/install_decl_perm/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_decl_perm
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.bp b/core/tests/coretests/apks/install_jni_lib/Android.bp
index c1a6bd0b3d21..f20f59958736 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.bp
+++ b/core/tests/coretests/apks/install_jni_lib/Android.bp
@@ -14,6 +14,7 @@
cc_test_library {
name: "libframeworks_coretests_jni",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
srcs: ["com_android_frameworks_coretests_JNITest.cpp"],
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
new file mode 100644
index 000000000000..602b704a0a5d
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_jni_lib_open_from_apk",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
deleted file mode 100644
index 6b3b55ed39e9..000000000000
--- a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.bp b/core/tests/coretests/apks/install_loc_auto/Android.bp
new file mode 100644
index 000000000000..6393915ba283
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_auto/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_loc_auto",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.mk b/core/tests/coretests/apks/install_loc_auto/Android.mk
deleted file mode 100644
index 6435f3624a15..000000000000
--- a/core/tests/coretests/apks/install_loc_auto/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_auto
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.bp b/core/tests/coretests/apks/install_loc_internal/Android.bp
new file mode 100644
index 000000000000..770aaa511b9d
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_internal/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_loc_internal",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.mk b/core/tests/coretests/apks/install_loc_internal/Android.mk
deleted file mode 100644
index 8cc8b8e0e778..000000000000
--- a/core/tests/coretests/apks/install_loc_internal/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_internal
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.bp b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
new file mode 100644
index 000000000000..177940102e83
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_loc_sdcard",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.mk b/core/tests/coretests/apks/install_loc_sdcard/Android.mk
deleted file mode 100644
index e1411c2276a5..000000000000
--- a/core/tests/coretests/apks/install_loc_sdcard/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_sdcard
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/core/tests/coretests/apks/install_loc_unspecified/Android.bp
new file mode 100644
index 000000000000..21c0f82b44ff
--- /dev/null
+++ b/core/tests/coretests/apks/install_loc_unspecified/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_loc_unspecified",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.mk b/core/tests/coretests/apks/install_loc_unspecified/Android.mk
deleted file mode 100644
index 0741d04b61d5..000000000000
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_loc_unspecified
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp
new file mode 100644
index 000000000000..249242e239e4
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_multi_package",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
deleted file mode 100644
index 3f163def9ce0..000000000000
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_multi_package
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-#include $(BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.bp b/core/tests/coretests/apks/install_use_perm_good/Android.bp
new file mode 100644
index 000000000000..bb41ebb2fdca
--- /dev/null
+++ b/core/tests/coretests/apks/install_use_perm_good/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_use_perm_good",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.mk b/core/tests/coretests/apks/install_use_perm_good/Android.mk
deleted file mode 100644
index e2661a13793a..000000000000
--- a/core/tests/coretests/apks/install_use_perm_good/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_use_perm_good
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.bp b/core/tests/coretests/apks/install_uses_feature/Android.bp
new file mode 100644
index 000000000000..0ec747b0f151
--- /dev/null
+++ b/core/tests/coretests/apks/install_uses_feature/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_uses_feature",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.mk b/core/tests/coretests/apks/install_uses_feature/Android.mk
deleted file mode 100644
index b60d734fe635..000000000000
--- a/core/tests/coretests/apks/install_uses_feature/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_uses_feature
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.bp b/core/tests/coretests/apks/install_verifier_bad/Android.bp
new file mode 100644
index 000000000000..1265739a3107
--- /dev/null
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_verifier_bad",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
deleted file mode 100644
index 745b4d32ccc4..000000000000
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_verifier_bad
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.bp b/core/tests/coretests/apks/install_verifier_good/Android.bp
new file mode 100644
index 000000000000..4911ffbd2020
--- /dev/null
+++ b/core/tests/coretests/apks/install_verifier_good/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_install_verifier_good",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
deleted file mode 100644
index 150fd8dd8701..000000000000
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := install_verifier_good
-
-LOCAL_USE_AAPT2 := true
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/keyset/Android.bp b/core/tests/coretests/apks/keyset/Android.bp
new file mode 100644
index 000000000000..e252b081341a
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/Android.bp
@@ -0,0 +1,120 @@
+//apks signed by keyset_A
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sa_unone",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "uNone/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sa_ua",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sa_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sa_uab",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "uAB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sa_ua_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "uAuB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_permdef_sa_unone",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "permDef/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_permuse_sa_ua_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_B
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sb_ua",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_B_cert",
+ manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sb_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_B_cert",
+ manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_permuse_sb_ua_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_B_cert",
+ manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and keyset_B
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sab_ua",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
+ manifest: "uA/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and unit_test
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_sau_ub",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksCoreTests_keyset_A_cert",
+ additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
+ manifest: "uB/AndroidManifest.xml",
+}
+
+//apks signed by platform only
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_splat_api",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: "platform",
+ manifest: "api_test/AndroidManifest.xml",
+}
+
+//apks signed by platform and keyset_A
+android_test_helper_app {
+ name: "FrameworksCoreTests_keyset_splata_api",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: "platform",
+ additional_certificates: [":FrameworksCoreTests_keyset_A_cert"],
+ manifest: "api_test/AndroidManifest.xml",
+}
diff --git a/core/tests/coretests/apks/keyset/Android.mk b/core/tests/coretests/apks/keyset/Android.mk
deleted file mode 100644
index 306dc90118f7..000000000000
--- a/core/tests/coretests/apks/keyset/Android.mk
+++ /dev/null
@@ -1,108 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#apks signed by keyset_A
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_unone
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uNone/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_uab
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uAB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sa_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := uAuB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permdef_sa_unone
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := permDef/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permuse_sa_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_B
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sb_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sb_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_permuse_sb_ua_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_A and keyset_B
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sab_ua
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by keyset_A and unit_test
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_sau_ub
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
-LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by platform only
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_splat_api
-LOCAL_CERTIFICATE := platform
-LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-#apks signed by platform and keyset_A
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := keyset_splata_api
-LOCAL_CERTIFICATE := platform
-LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_A
-LOCAL_MANIFEST_FILE := api_test/AndroidManifest.xml
-include $(FrameworkCoreTests_BUILD_PACKAGE) \ No newline at end of file
diff --git a/core/tests/coretests/apks/locales/Android.bp b/core/tests/coretests/apks/locales/Android.bp
new file mode 100644
index 000000000000..4a730ef53404
--- /dev/null
+++ b/core/tests/coretests/apks/locales/Android.bp
@@ -0,0 +1,6 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_locales",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+
+ srcs: ["**/*.java"],
+}
diff --git a/core/tests/coretests/apks/locales/Android.mk b/core/tests/coretests/apks/locales/Android.mk
deleted file mode 100644
index 9cb13dd4cd0e..000000000000
--- a/core/tests/coretests/apks/locales/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := locales
-
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/version/Android.bp b/core/tests/coretests/apks/version/Android.bp
new file mode 100644
index 000000000000..371ccfc301cb
--- /dev/null
+++ b/core/tests/coretests/apks/version/Android.bp
@@ -0,0 +1,54 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_1",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 1",
+ "--version-name 1.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_2",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 2",
+ "--version-name 2.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_3",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 3",
+ "--version-name 3.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_1_diff",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 1",
+ "--version-name 1.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
+
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_2_diff",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 2",
+ "--version-name 2.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
diff --git a/core/tests/coretests/apks/version/Android.mk b/core/tests/coretests/apks/version/Android.mk
deleted file mode 100644
index 3635a581dee5..000000000000
--- a/core/tests/coretests/apks/version/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_2
-LOCAL_AAPT_FLAGS := --version-code 2 --version-name 2.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_3
-LOCAL_AAPT_FLAGS := --version-code 3 --version-name 3.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1_diff
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test_diff
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_2_diff
-LOCAL_AAPT_FLAGS := --version-code 2 --version-name 2.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test_diff
-include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/version_nosys/Android.bp b/core/tests/coretests/apks/version_nosys/Android.bp
new file mode 100644
index 000000000000..575667822393
--- /dev/null
+++ b/core/tests/coretests/apks/version_nosys/Android.bp
@@ -0,0 +1,10 @@
+android_test_helper_app {
+ name: "FrameworksCoreTests_version_1_nosys",
+ defaults: ["FrameworksCoreTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ aaptflags: [
+ "--version-code 1",
+ "--version-name 1.0",
+ ],
+ certificate: ":FrameworksCoreTests_unit_test_cert",
+}
diff --git a/core/tests/coretests/apks/version_nosys/Android.mk b/core/tests/coretests/apks/version_nosys/Android.mk
deleted file mode 100644
index bbc8e12afe8d..000000000000
--- a/core/tests/coretests/apks/version_nosys/Android.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := version_1_nosys
-LOCAL_AAPT_FLAGS := --version-code 1 --version-name 1.0
-LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/unit_test
-include $(FrameworkCoreTests_BUILD_PACKAGE)
-
diff --git a/core/tests/coretests/certs/Android.bp b/core/tests/coretests/certs/Android.bp
new file mode 100644
index 000000000000..bd5c8293f6f6
--- /dev/null
+++ b/core/tests/coretests/certs/Android.bp
@@ -0,0 +1,14 @@
+android_app_certificate {
+ name: "FrameworksCoreTests_keyset_A_cert",
+ certificate: "keyset_A",
+}
+
+android_app_certificate {
+ name: "FrameworksCoreTests_keyset_B_cert",
+ certificate: "keyset_B",
+}
+
+android_app_certificate {
+ name: "FrameworksCoreTests_unit_test_cert",
+ certificate: "unit_test",
+}
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 5731daa0b2a9..4ae9494aa362 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -99,7 +99,8 @@ public class PasswordMetricsTest {
@Test
public void testComputeForPassword_metrics() {
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A");
+ final PasswordMetrics metrics =
+ PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes());
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
@@ -112,32 +113,32 @@ public class PasswordMetricsTest {
@Test
public void testComputeForPassword_quality() {
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
- PasswordMetrics.computeForPassword("a1").quality);
+ PasswordMetrics.computeForPassword("a1".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
- PasswordMetrics.computeForPassword("a").quality);
+ PasswordMetrics.computeForPassword("a".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
- PasswordMetrics.computeForPassword("*~&%$").quality);
+ PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
- PasswordMetrics.computeForPassword("1").quality);
+ PasswordMetrics.computeForPassword("1".getBytes()).quality);
// contains a long sequence so isn't complex
assertEquals(PASSWORD_QUALITY_NUMERIC,
- PasswordMetrics.computeForPassword("1234").quality);
+ PasswordMetrics.computeForPassword("1234".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- PasswordMetrics.computeForPassword("").quality);
+ PasswordMetrics.computeForPassword("".getBytes()).quality);
}
@Test
public void testMaxLengthSequence() {
- assertEquals(4, PasswordMetrics.maxLengthSequence("1234"));
- assertEquals(5, PasswordMetrics.maxLengthSequence("13579"));
- assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd"));
- assertEquals(3, PasswordMetrics.maxLengthSequence("aabc"));
- assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio"));
- assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC"));
+ assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes()));
+ assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes()));
+ assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes()));
+ assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes()));
+ assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes()));
+ assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes()));
// anything that repeats
- assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;"));
+ assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes()));
// ordered, but not composed of alphas or digits
- assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>"));
+ assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes()));
}
@Test
@@ -158,8 +159,8 @@ public class PasswordMetricsTest {
assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
new PasswordMetrics(PASSWORD_QUALITY_COMPLEX, 4));
- metrics0 = PasswordMetrics.computeForPassword("1234abcd,./");
- metrics1 = PasswordMetrics.computeForPassword("1234abcd,./");
+ metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
+ metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
assertEquals(metrics0, metrics1);
metrics1.letters++;
assertNotEquals(metrics0, metrics1);
@@ -197,7 +198,7 @@ public class PasswordMetricsTest {
@Test
public void testDetermineComplexity_none() {
assertEquals(PASSWORD_COMPLEXITY_NONE,
- PasswordMetrics.computeForPassword("").determineComplexity());
+ PasswordMetrics.computeForPassword("".getBytes()).determineComplexity());
}
@Test
@@ -209,61 +210,61 @@ public class PasswordMetricsTest {
@Test
public void testDetermineComplexity_lowNumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("1234").determineComplexity());
+ PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("124").determineComplexity());
+ PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!").determineComplexity());
+ PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!1").determineComplexity());
+ PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("1238").determineComplexity());
+ PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!c").determineComplexity());
+ PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!1").determineComplexity());
+ PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("12389647!").determineComplexity());
+ PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("alphabetic!").determineComplexity());
+ PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("alphanumeric123!").determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword(
+ "alphanumeric123!".getBytes()).determineComplexity());
}
@Test
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 5dbcb3c46b50..82bd588ea9ff 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -19,6 +19,7 @@ package android.database.sqlite;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.Context;
import android.database.DatabaseUtils;
@@ -54,44 +55,52 @@ public class SQLiteCompatibilityWalFlagsTest {
@Test
public void testParseConfig() {
SQLiteCompatibilityWalFlags.init("");
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
-
SQLiteCompatibilityWalFlags.init(null);
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=false,wal_syncmode=OFF");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
- assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ // Ensure that legacy compatibility wal isn't turned on by the old flag.
+ SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=OFF");
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
+ try {
+ SQLiteCompatibilityWalFlags.getWALSyncMode();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+
SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
- assertEquals(SQLiteGlobal.isCompatibilityWalSupported(),
- SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+ try {
+ SQLiteCompatibilityWalFlags.getWALSyncMode();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
+ SQLiteCompatibilityWalFlags.init("legacy_compatibility_wal_enabled=true");
+ assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(SQLiteGlobal.getWALSyncMode(),
SQLiteCompatibilityWalFlags.getWALSyncMode());
- assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=VALUE");
+ assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
+ assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
SQLiteCompatibilityWalFlags.init("truncate_size=1024");
assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.reset();
SQLiteCompatibilityWalFlags.init("Invalid value");
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
}
@Test
public void testApplyFlags() {
Context ctx = InstrumentationRegistry.getContext();
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=NORMAL");
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=NORMAL");
mDatabase = SQLiteDatabase
.openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
@@ -100,5 +109,22 @@ public class SQLiteCompatibilityWalFlagsTest {
assertEquals("Normal mode (1) is expected", "1", syncMode);
}
+ @Test
+ public void testApplyFlags_thenDisableWriteAheadLogging() {
+ Context ctx = InstrumentationRegistry.getContext();
+
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=FULL");
+ mDatabase = SQLiteDatabase
+ .openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
+ mDatabase.disableWriteAheadLogging();
+ String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
+ assertEquals(SQLiteGlobal.getDefaultJournalMode(), journalMode.toUpperCase());
+ String syncMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA synchronous", null);
+ // TODO: This is the old behaviour and seems incorrect. The specified wal_syncmode was only
+ // intended to be used if the database is in WAL mode, and we should revert to the global
+ // default sync mode if WAL is disabled.
+ assertEquals("Normal mode (2) is expected", "2", syncMode);
+ }
}
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 17e9654b651a..5d5754bc41be 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -18,15 +18,11 @@ package android.provider;
import static android.provider.DeviceConfig.OnPropertyChangedListener;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.fail;
+import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.os.Bundle;
-import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -37,8 +33,8 @@ import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@@ -51,8 +47,6 @@ public class DeviceConfigTest {
private static final String sValue = "value1";
private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
- private final Object mLock = new Object();
-
@After
public void cleanUp() {
deleteViaContentProvider(sNamespace, sKey);
@@ -61,14 +55,14 @@ public class DeviceConfigTest {
@Test
public void getProperty_empty() {
String result = DeviceConfig.getProperty(sNamespace, sKey);
- assertNull(result);
+ assertThat(result).isNull();
}
@Test
public void setAndGetProperty_sameNamespace() {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
- assertEquals(sValue, result);
+ assertThat(result).isEqualTo(sValue);
}
@Test
@@ -76,7 +70,7 @@ public class DeviceConfigTest {
String newNamespace = "namespace2";
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(newNamespace, sKey);
- assertNull(result);
+ assertThat(result).isNull();
}
@Test
@@ -86,9 +80,9 @@ public class DeviceConfigTest {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(newNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
- assertEquals(sValue, result);
+ assertThat(result).isEqualTo(sValue);
result = DeviceConfig.getProperty(newNamespace, sKey);
- assertEquals(newValue, result);
+ assertThat(result).isEqualTo(newValue);
// clean up
deleteViaContentProvider(newNamespace, sKey);
@@ -100,59 +94,30 @@ public class DeviceConfigTest {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(sNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
- assertEquals(newValue, result);
+ assertThat(result).isEqualTo(newValue);
}
@Test
- public void testListener() {
- setPropertyAndAssertSuccessfulChange(sNamespace, sKey, sValue);
- }
+ public void testListener() throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ OnPropertyChangedListener changeListener = (namespace, name, value) -> {
+ assertThat(namespace).isEqualTo(sNamespace);
+ assertThat(name).isEqualTo(sKey);
+ assertThat(value).isEqualTo(sValue);
+ countDownLatch.countDown();
+ };
- private void setPropertyAndAssertSuccessfulChange(String setNamespace, String setName,
- String setValue) {
- final AtomicBoolean success = new AtomicBoolean();
-
- OnPropertyChangedListener changeListener = new OnPropertyChangedListener() {
- @Override
- public void onPropertyChanged(String namespace, String name, String value) {
- assertEquals(setNamespace, namespace);
- assertEquals(setName, name);
- assertEquals(setValue, value);
- success.set(true);
-
- synchronized (mLock) {
- mLock.notifyAll();
- }
- }
- };
- Executor executor = ActivityThread.currentApplication().getMainExecutor();
- DeviceConfig.addOnPropertyChangedListener(setNamespace, executor, changeListener);
try {
- DeviceConfig.setProperty(setNamespace, setName, setValue, false);
-
- final long startTimeMillis = SystemClock.uptimeMillis();
- synchronized (mLock) {
- while (true) {
- if (success.get()) {
- return;
- }
- final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
- if (elapsedTimeMillis >= WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS) {
- fail("Could not change setting for "
- + WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS + " ms");
- }
- final long remainingTimeMillis = WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS
- - elapsedTimeMillis;
- try {
- mLock.wait(remainingTimeMillis);
- } catch (InterruptedException ie) {
- /* ignore */
- }
- }
- }
+ DeviceConfig.addOnPropertyChangedListener(sNamespace,
+ ActivityThread.currentApplication().getMainExecutor(), changeListener);
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
} finally {
DeviceConfig.removeOnPropertyChangedListener(changeListener);
}
+
}
private static boolean deleteViaContentProvider(String namespace, String key) {
@@ -160,7 +125,7 @@ public class DeviceConfigTest {
String compositeName = namespace + "/" + key;
Bundle result = resolver.call(
DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, compositeName, null);
- assertNotNull(result);
+ assertThat(result).isNotNull();
return compositeName.equals(result.getString(Settings.NameValueTable.VALUE));
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 71ce02d859f5..23ab05e952a3 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -129,6 +129,29 @@ public class InsetsAnimationControlImplTest {
assertPosition(navParams.matrix, new Rect(400, 0, 500, 500), new Rect(460, 0, 560, 500));
}
+ @Test
+ public void testFinishing() {
+ when(mMockController.getState()).thenReturn(mInsetsState);
+ mController.finish(sideBars());
+ mController.applyChangeInsets(mInsetsState);
+ assertFalse(mInsetsState.getSource(TYPE_TOP_BAR).isVisible());
+ assertTrue(mInsetsState.getSource(TYPE_NAVIGATION_BAR).isVisible());
+ assertEquals(Insets.of(0, 0, 100, 0), mController.getCurrentInsets());
+ verify(mMockController).notifyFinished(eq(mController), eq(sideBars()));
+ }
+
+ @Test
+ public void testCancelled() {
+ mController.onCancelled();
+ try {
+ mController.changeInsets(Insets.NONE);
+ fail("Expected exception to be thrown");
+ } catch (IllegalStateException ignored) {
+ }
+ verify(mMockListener).onCancelled();
+ mController.finish(sideBars());
+ }
+
private void assertPosition(Matrix m, Rect original, Rect transformed) {
RectF rect = new RectF(original);
rect.offsetTo(0, 0);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 731d5644504b..d71bde837d6f 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -20,6 +20,7 @@ import static android.view.InsetsState.TYPE_IME;
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.WindowInsets.Type.topBar;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -48,6 +49,9 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.concurrent.CountDownLatch;
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
@@ -80,6 +84,8 @@ public class InsetsControllerTest {
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
rect, rect, SOFT_INPUT_ADJUST_RESIZE);
+ mController.onFrameChanged(new Rect(0, 0, 100, 100));
+ mController.getState().setDisplayFrame(new Rect(0, 0, 100, 100));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -101,6 +107,19 @@ public class InsetsControllerTest {
}
@Test
+ public void testControlsRevoked_duringAnim() {
+ InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
+
+ WindowInsetsAnimationControlListener mockListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(topBar(), mockListener);
+ verify(mockListener).onReady(any(), anyInt());
+ mController.onControlsChanged(new InsetsSourceControl[0]);
+ verify(mockListener).onCancelled();
+ }
+
+ @Test
public void testFrameDoesntMatchDisplay() {
mController.onFrameChanged(new Rect(0, 0, 100, 100));
mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
@@ -119,24 +138,21 @@ public class InsetsControllerTest {
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // since there is no focused view, forcefully make IME visible.
+ mController.applyImeVisibility(true /* setVisible */);
mController.show(Type.all());
// quickly jump to final state by cancelling it.
mController.cancelExistingAnimation();
assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
- // no focused view, no IME.
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+ mController.applyImeVisibility(false /* setVisible */);
mController.hide(Type.all());
mController.cancelExistingAnimation();
assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
-
- mController.show(Type.ime());
- mController.cancelExistingAnimation();
- // no focused view, no IME.
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -292,6 +308,35 @@ public class InsetsControllerTest {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+ @Test
+ public void testAnimationEndState_controller() throws Exception {
+ InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ WindowInsetsAnimationControlListener mockListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(topBar(), mockListener);
+
+ ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
+ ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
+ verify(mockListener).onReady(controllerCaptor.capture(), anyInt());
+ controllerCaptor.getValue().finish(0 /* shownTypes */);
+ });
+ waitUntilNextFrame();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ assertFalse(mController.getSourceConsumer(TYPE_TOP_BAR).isVisible());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ private void waitUntilNextFrame() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
+ latch::countDown, null /* token */);
+ latch.await();
+ }
+
private InsetsSourceControl[] prepareControls() {
final InsetsSourceControl navBar = new InsetsSourceControl(TYPE_NAVIGATION_BAR, mLeash,
new Point());
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index b6717e16256f..013408e0bd12 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -157,7 +157,7 @@ public class ContentCaptureSessionTest {
}
@Override
- public void internalNotifyViewHierarchyEvent(boolean started) {
+ public void internalNotifyViewTreeEvent(boolean started) {
throw new UnsupportedOperationException("should not have been called");
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
new file mode 100644
index 000000000000..e4e9cde5e977
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class LabeledIntentTest {
+ private static final String TITLE_WITHOUT_ENTITY = "Map";
+ private static final String TITLE_WITH_ENTITY = "Map NW14D1";
+ private static final String DESCRIPTION = "Check the map";
+ private static final Intent INTENT =
+ new Intent(Intent.ACTION_VIEW).setDataAndNormalize(Uri.parse("http://www.android.com"));
+ private static final int REQUEST_CODE = 42;
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @Test
+ public void resolve_preferTitleWithEntity() {
+ LabeledIntent labeledIntent = new LabeledIntent(
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
+ DESCRIPTION,
+ INTENT,
+ REQUEST_CODE
+ );
+
+ LabeledIntent.Result result =
+ labeledIntent.resolve(mContext, /*titleChooser*/ null);
+
+ assertThat(result).isNotNull();
+ assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITH_ENTITY);
+ assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+ Intent intent = result.resolvedIntent;
+ assertThat(intent.getAction()).isEqualTo(intent.getAction());
+ assertThat(intent.getComponent()).isNotNull();
+ }
+
+ @Test
+ public void resolve_useAvailableTitle() {
+ LabeledIntent labeledIntent = new LabeledIntent(
+ TITLE_WITHOUT_ENTITY,
+ null,
+ DESCRIPTION,
+ INTENT,
+ REQUEST_CODE
+ );
+
+ LabeledIntent.Result result =
+ labeledIntent.resolve(mContext, /*titleChooser*/ null);
+
+ assertThat(result).isNotNull();
+ assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
+ assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+ Intent intent = result.resolvedIntent;
+ assertThat(intent.getAction()).isEqualTo(intent.getAction());
+ assertThat(intent.getComponent()).isNotNull();
+ }
+
+ @Test
+ public void resolve_titleChooser() {
+ LabeledIntent labeledIntent = new LabeledIntent(
+ TITLE_WITHOUT_ENTITY,
+ null,
+ DESCRIPTION,
+ INTENT,
+ REQUEST_CODE
+ );
+
+ LabeledIntent.Result result =
+ labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> "chooser");
+
+ assertThat(result).isNotNull();
+ assertThat(result.remoteAction.getTitle()).isEqualTo("chooser");
+ assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+ Intent intent = result.resolvedIntent;
+ assertThat(intent.getAction()).isEqualTo(intent.getAction());
+ assertThat(intent.getComponent()).isNotNull();
+ }
+
+ @Test
+ public void resolve_titleChooserReturnsNull() {
+ LabeledIntent labeledIntent = new LabeledIntent(
+ TITLE_WITHOUT_ENTITY,
+ null,
+ DESCRIPTION,
+ INTENT,
+ REQUEST_CODE
+ );
+
+ LabeledIntent.Result result =
+ labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> null);
+
+ assertThat(result).isNotNull();
+ assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
+ assertThat(result.remoteAction.getContentDescription()).isEqualTo(DESCRIPTION);
+ Intent intent = result.resolvedIntent;
+ assertThat(intent.getAction()).isEqualTo(intent.getAction());
+ assertThat(intent.getComponent()).isNotNull();
+ }
+
+
+ @Test
+ public void resolve_missingTitle() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ new LabeledIntent(
+ null,
+ null,
+ DESCRIPTION,
+ INTENT,
+ REQUEST_CODE
+ ));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
index 73d3eec734d7..743818cd3d4e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
@@ -58,9 +58,12 @@ public class LegacyIntentFactoryTest {
null,
null,
null,
+ null,
+ null,
+ null,
null);
- List<TextClassifierImpl.LabeledIntent> intents = mLegacyIntentFactory.create(
+ List<LabeledIntent> intents = mLegacyIntentFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
/* foreignText */ false,
@@ -68,8 +71,8 @@ public class LegacyIntentFactoryTest {
classificationResult);
assertThat(intents).hasSize(1);
- TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- Intent intent = labeledIntent.getIntent();
+ LabeledIntent labeledIntent = intents.get(0);
+ Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT);
assertThat(
@@ -89,9 +92,12 @@ public class LegacyIntentFactoryTest {
null,
null,
null,
+ null,
+ null,
+ null,
null);
- List<TextClassifierImpl.LabeledIntent> intents = mLegacyIntentFactory.create(
+ List<LabeledIntent> intents = mLegacyIntentFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
/* foreignText */ true,
@@ -99,7 +105,7 @@ public class LegacyIntentFactoryTest {
classificationResult);
assertThat(intents).hasSize(2);
- assertThat(intents.get(0).getIntent().getAction()).isEqualTo(Intent.ACTION_DEFINE);
- assertThat(intents.get(1).getIntent().getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
+ assertThat(intents.get(0).intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
+ assertThat(intents.get(1).intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
index d9dac314fc7c..9fd9e8eb2690 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
@@ -40,7 +40,7 @@ import java.util.List;
public class TemplateClassificationIntentFactoryTest {
private static final String TEXT = "text";
- private static final String TITLE = "Map";
+ private static final String TITLE_WITHOUT_ENTITY = "Map";
private static final String DESCRIPTION = "Opens in Maps";
private static final String ACTION = Intent.ACTION_VIEW;
@@ -69,9 +69,12 @@ public class TemplateClassificationIntentFactoryTest {
null,
null,
null,
+ null,
+ null,
+ null,
createRemoteActionTemplates());
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateClassificationIntentFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
@@ -80,14 +83,14 @@ public class TemplateClassificationIntentFactoryTest {
classificationResult);
assertThat(intents).hasSize(2);
- TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
- Intent intent = labeledIntent.getIntent();
+ LabeledIntent labeledIntent = intents.get(0);
+ assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+ Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
labeledIntent = intents.get(1);
- intent = labeledIntent.getIntent();
+ intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@@ -105,9 +108,12 @@ public class TemplateClassificationIntentFactoryTest {
null,
null,
null,
+ null,
+ null,
+ null,
createRemoteActionTemplates());
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateClassificationIntentFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
@@ -116,9 +122,9 @@ public class TemplateClassificationIntentFactoryTest {
classificationResult);
assertThat(intents).hasSize(1);
- TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
- Intent intent = labeledIntent.getIntent();
+ LabeledIntent labeledIntent = intents.get(0);
+ assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+ Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@@ -126,7 +132,8 @@ public class TemplateClassificationIntentFactoryTest {
private static RemoteActionTemplate[] createRemoteActionTemplates() {
return new RemoteActionTemplate[]{
new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ null,
DESCRIPTION,
ACTION,
null,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
index a1158a7cbb6c..186073475bf4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
@@ -38,7 +38,8 @@ import java.util.List;
public class TemplateIntentFactoryTest {
private static final String TEXT = "text";
- private static final String TITLE = "Map";
+ private static final String TITLE_WITHOUT_ENTITY = "Map";
+ private static final String TITLE_WITH_ENTITY = "Map NW14D1";
private static final String DESCRIPTION = "Check the map";
private static final String ACTION = Intent.ACTION_VIEW;
private static final String DATA = Uri.parse("http://www.android.com").toString();
@@ -69,7 +70,8 @@ public class TemplateIntentFactoryTest {
@Test
public void create_full() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
DESCRIPTION,
ACTION,
DATA,
@@ -81,15 +83,16 @@ public class TemplateIntentFactoryTest {
REQUEST_CODE
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
assertThat(intents).hasSize(1);
- TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
- assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
- assertThat(labeledIntent.getRequestCode()).isEqualTo(REQUEST_CODE);
- Intent intent = labeledIntent.getIntent();
+ LabeledIntent labeledIntent = intents.get(0);
+ assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+ assertThat(labeledIntent.titleWithEntity).isEqualTo(TITLE_WITH_ENTITY);
+ assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
+ assertThat(labeledIntent.requestCode).isEqualTo(REQUEST_CODE);
+ Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.getData().toString()).isEqualTo(DATA);
assertThat(intent.getType()).isEqualTo(TYPE);
@@ -104,7 +107,8 @@ public class TemplateIntentFactoryTest {
@Test
public void normalizesScheme() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
DESCRIPTION,
ACTION,
"HTTp://www.android.com",
@@ -116,17 +120,18 @@ public class TemplateIntentFactoryTest {
REQUEST_CODE
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
- String data = intents.get(0).getIntent().getData().toString();
+ String data = intents.get(0).intent.getData().toString();
assertThat(data).isEqualTo("http://www.android.com");
}
@Test
public void create_minimal() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ null,
DESCRIPTION,
ACTION,
null,
@@ -138,16 +143,17 @@ public class TemplateIntentFactoryTest {
null
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
assertThat(intents).hasSize(1);
- TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
- assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
- assertThat(labeledIntent.getRequestCode()).isEqualTo(
- TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE);
- Intent intent = labeledIntent.getIntent();
+ LabeledIntent labeledIntent = intents.get(0);
+ assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
+ assertThat(labeledIntent.titleWithEntity).isNull();
+ assertThat(labeledIntent.description).isEqualTo(DESCRIPTION);
+ assertThat(labeledIntent.requestCode).isEqualTo(
+ LabeledIntent.DEFAULT_REQUEST_CODE);
+ Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.getData()).isNull();
assertThat(intent.getType()).isNull();
@@ -161,7 +167,7 @@ public class TemplateIntentFactoryTest {
public void invalidTemplate_nullTemplate() {
RemoteActionTemplate remoteActionTemplate = null;
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
assertThat(intents).isEmpty();
@@ -170,7 +176,8 @@ public class TemplateIntentFactoryTest {
@Test
public void invalidTemplate_nonEmptyPackageName() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
DESCRIPTION,
ACTION,
DATA,
@@ -182,7 +189,7 @@ public class TemplateIntentFactoryTest {
REQUEST_CODE
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
assertThat(intents).isEmpty();
@@ -192,6 +199,7 @@ public class TemplateIntentFactoryTest {
public void invalidTemplate_emptyTitle() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
null,
+ null,
DESCRIPTION,
ACTION,
null,
@@ -203,7 +211,7 @@ public class TemplateIntentFactoryTest {
null
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
assertThat(intents).isEmpty();
@@ -212,7 +220,8 @@ public class TemplateIntentFactoryTest {
@Test
public void invalidTemplate_emptyDescription() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
null,
ACTION,
null,
@@ -224,7 +233,7 @@ public class TemplateIntentFactoryTest {
null
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
assertThat(intents).isEmpty();
@@ -233,7 +242,8 @@ public class TemplateIntentFactoryTest {
@Test
public void invalidTemplate_emptyIntentAction() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
+ TITLE_WITHOUT_ENTITY,
+ TITLE_WITH_ENTITY,
DESCRIPTION,
null,
null,
@@ -245,7 +255,7 @@ public class TemplateIntentFactoryTest {
null
);
- List<TextClassifierImpl.LabeledIntent> intents =
+ List<LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
assertThat(intents).isEmpty();
diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp
new file mode 100644
index 000000000000..1f742c208ba2
--- /dev/null
+++ b/core/tests/utillib/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+ name: "frameworks-core-util-lib",
+
+ srcs: ["**/*.java"],
+
+ static_libs: ["junit"],
+ libs: ["android.test.base"],
+}
diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk
deleted file mode 100644
index be1ab1f73d9f..000000000000
--- a/core/tests/utillib/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE := frameworks-core-util-lib
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_JAVA_LIBRARIES := android.test.base
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index aaf40b41bc31..83c8b01e6ad6 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -599,9 +599,6 @@ public abstract class BaseCanvas {
int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
@NonNull Paint paint) {
checkRange(verts.length, vertOffset, vertexCount);
- if (isHardwareAccelerated()) {
- return;
- }
if (texs != null) {
checkRange(texs.length, texOffset, vertexCount);
}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 60ce595b82b8..920fb4cffbca 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -836,7 +836,7 @@ public final class Bitmap implements Parcelable {
* @return A bitmap that represents the specified subset of source
* @throws IllegalArgumentException if the x, y, width, height values are
* outside of the dimensions of the source bitmap, or width is <= 0,
- * or height is <= 0
+ * or height is <= 0, or if the source bitmap has already been recycled
*/
public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
@Nullable Matrix m, boolean filter) {
@@ -849,6 +849,9 @@ public final class Bitmap implements Parcelable {
if (y + height > source.getHeight()) {
throw new IllegalArgumentException("y + height must be <= bitmap.height()");
}
+ if (source.isRecycled()) {
+ throw new IllegalArgumentException("cannot use a recycled source in createBitmap");
+ }
// check if we can just return our argument unchanged
if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
index 3b9a348047ba..660614895603 100644
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -135,6 +135,9 @@ bool DisplayEventDispatcher::processPendingEvents(
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, ev.config.configId);
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index d2addba61679..5381c0174cb0 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -40,6 +40,8 @@ private:
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
+ virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) = 0;
virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index df1537e2d824..1bd30eb5371b 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -161,7 +161,7 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
SkAutoCanvasRestore acr2(canvas, shouldClip);
canvas->setMatrix(mProjectedDisplayList->mParentMatrix);
if (shouldClip) {
- clipOutline(*mProjectedDisplayList->mProjectedOutline, canvas, nullptr);
+ canvas->clipPath(*mProjectedDisplayList->mProjectedOutline->getPath());
}
drawBackwardsProjectedNodes(canvas, *mProjectedDisplayList);
}
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 6da80628be60..6c04232ab7f5 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -117,6 +117,7 @@ void CacheManager::configureContext(GrContextOptions* contextOptions, const void
auto& cache = skiapipeline::ShaderCache::get();
cache.initShaderDiskCache(identity, size);
contextOptions->fPersistentCache = &cache;
+ contextOptions->fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
}
void CacheManager::trimMemory(TrimMemoryMode mode) {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 733b866d9c4c..abf083789c23 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -759,11 +759,11 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() {
void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
+ mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
+ mLocked.additionalMouseResources.clear();
+ mLocked.animationResources.clear();
if (mLocked.presentation == PRESENTATION_POINTER) {
- mLocked.additionalMouseResources.clear();
- mLocked.animationResources.clear();
- mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources, mLocked.viewport.displayId);
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index dbb581fe54b2..d1b39b350d73 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -11,7 +11,7 @@ package com.android.location.provider {
method public android.os.IBinder getBinder();
method public boolean isEnabled();
method @Deprecated protected void onDisable();
- method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+ method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Deprecated protected void onEnable();
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 7cd7207c26a0..fa113a8aa3ef 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -240,8 +240,10 @@ public abstract class LocationProviderBase {
protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
/**
- * Dump debug information.
+ * @deprecated This callback will never be invoked on Android Q and above. This method may be
+ * removed in the future. Prefer to dump provider state via the containing service instead.
*/
+ @Deprecated
protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
/**
@@ -336,10 +338,5 @@ public abstract class LocationProviderBase {
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- onDump(fd, pw, args);
- }
}
}
diff --git a/media/apex/java/android/media/MediaConstants.java b/media/apex/java/android/media/MediaConstants.java
index 65b6f55a068a..776c1ba3f82f 100644
--- a/media/apex/java/android/media/MediaConstants.java
+++ b/media/apex/java/android/media/MediaConstants.java
@@ -27,6 +27,7 @@ class MediaConstants {
static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE";
+ static final String KEY_TOKEN_EXTRAS = "android.media.key.TOKEN_EXTRAS";
private MediaConstants() {
}
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
index 4ea384ac70b2..2709df0e060f 100644
--- a/media/apex/java/android/media/MediaController2.java
+++ b/media/apex/java/android/media/MediaController2.java
@@ -21,6 +21,7 @@ import static android.media.MediaConstants.KEY_PACKAGE_NAME;
import static android.media.MediaConstants.KEY_PID;
import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -264,6 +265,7 @@ public class MediaController2 implements AutoCloseable {
Session2CommandGroup allowedCommands =
connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
+ Bundle tokenExtras = connectionResult.getBundle(KEY_TOKEN_EXTRAS);
if (DEBUG) {
Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
+ ", allowedCommands=" + allowedCommands);
@@ -282,7 +284,7 @@ public class MediaController2 implements AutoCloseable {
// so can be used without worrying about deadlock.
sessionBinder.linkToDeath(mDeathRecipient, 0);
mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
- mSessionToken.getPackageName(), sessionBinder);
+ mSessionToken.getPackageName(), sessionBinder, tokenExtras);
}
mCallbackExecutor.execute(() -> {
mCallback.onConnected(MediaController2.this, allowedCommands);
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index 4c6945ae8d3f..148e16c68cee 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -21,6 +21,7 @@ import static android.media.MediaConstants.KEY_PACKAGE_NAME;
import static android.media.MediaConstants.KEY_PID;
import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -94,7 +95,8 @@ public class MediaSession2 implements AutoCloseable {
private ForegroundServiceEventCallback mForegroundServiceEventCallback;
MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
- @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
+ @NonNull Executor callbackExecutor, @NonNull SessionCallback callback,
+ Bundle tokenExtras) {
synchronized (MediaSession2.class) {
if (SESSION_ID_LIST.contains(id)) {
throw new IllegalStateException("Session ID must be unique. ID=" + id);
@@ -109,7 +111,7 @@ public class MediaSession2 implements AutoCloseable {
mCallback = callback;
mSessionStub = new Session2Link(this);
mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
- mSessionStub);
+ mSessionStub, tokenExtras);
mSessionManager = (MediaSessionManager) mContext.getSystemService(
Context.MEDIA_SESSION_SERVICE);
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
@@ -339,6 +341,7 @@ public class MediaSession2 implements AutoCloseable {
connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
controllerInfo.mAllowedCommands);
connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive());
+ connectionResult.putBundle(KEY_TOKEN_EXTRAS, mSessionToken.getExtras());
// Double check if session is still there, because close() can be called in
// another thread.
@@ -444,6 +447,7 @@ public class MediaSession2 implements AutoCloseable {
private PendingIntent mSessionActivity;
private Executor mCallbackExecutor;
private SessionCallback mCallback;
+ private Bundle mExtras;
/**
* Creates a builder for {@link MediaSession2}.
@@ -507,6 +511,18 @@ public class MediaSession2 implements AutoCloseable {
}
/**
+ * Set extras for the session token.
+ *
+ * @return The Builder to allow chaining
+ * @see Session2Token#getExtras()
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
* Build {@link MediaSession2}.
*
* @return a new session
@@ -525,7 +541,7 @@ public class MediaSession2 implements AutoCloseable {
mId = "";
}
MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
- mCallbackExecutor, mCallback);
+ mCallbackExecutor, mCallback, mExtras);
// Notify framework about the newly create session after the constructor is finished.
// Otherwise, framework may access the session before the initialization is finished.
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
index 238cc2b8ee7d..6680e408ded4 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -88,6 +89,7 @@ public final class Session2Token implements Parcelable {
private final String mServiceName;
private final Session2Link mSessionLink;
private final ComponentName mComponentName;
+ private final Bundle mExtras;
/**
* Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
@@ -116,15 +118,18 @@ public final class Session2Token implements Parcelable {
mUid = uid;
mType = TYPE_SESSION_SERVICE;
mSessionLink = null;
+ mExtras = null;
}
- Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
+ Session2Token(int uid, int type, String packageName, Session2Link sessionLink,
+ Bundle tokenExtras) {
mUid = uid;
mType = type;
mPackageName = packageName;
mServiceName = null;
mComponentName = null;
mSessionLink = sessionLink;
+ mExtras = tokenExtras;
}
Session2Token(Parcel in) {
@@ -134,6 +139,7 @@ public final class Session2Token implements Parcelable {
mServiceName = in.readString();
mSessionLink = in.readParcelable(null);
mComponentName = ComponentName.unflattenFromString(in.readString());
+ mExtras = in.readBundle();
}
@Override
@@ -144,6 +150,7 @@ public final class Session2Token implements Parcelable {
dest.writeString(mServiceName);
dest.writeParcelable(mSessionLink, flags);
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
+ dest.writeBundle(mExtras);
}
@Override
@@ -207,6 +214,14 @@ public final class Session2Token implements Parcelable {
return mType;
}
+ /**
+ * @return extras of the token
+ */
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
Session2Link getSessionLink() {
return mSessionLink;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bd828eea8179..3fb2365cb006 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -36,6 +36,7 @@ import android.content.Context;
import android.content.Intent;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.projection.MediaProjection;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -5221,6 +5222,30 @@ public class AudioManager {
return AudioSystem.isHapticPlaybackSupported();
}
+ /**
+ * @hide
+ * Introspection API to retrieve audio product strategies.
+ * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
+ * audio product strategies, which is indexed by a weakly typed index in order to be extended
+ * by OEM without any needs of AOSP patches.
+ * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
+ * strategy refered either by its index or human readable string. It will allow clients
+ * application to start streaming data using these {@link AudioAttributes} on the selected
+ * device by Audio Policy Engine.
+ * @return a (possibly zero-length) array of
+ * {@see android.media.audiopolicy.AudioProductStrategy} objects.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull AudioProductStrategies getAudioProductStrategies() {
+ final IAudioService service = getService();
+ try {
+ return service.getAudioProductStrategies();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
//---------------------------------------------------------
// Inner classes
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9218e92e51a6..b2f970a99207 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -40,7 +40,7 @@ import java.util.Map;
*/
public class AudioSystem
{
- private static final boolean DEBUG_VOLUME = true;
+ private static final boolean DEBUG_VOLUME = false;
private static final String TAG = "AudioSystem";
/* These values must be kept in sync with system/audio.h */
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 571e67e1ccfc..abdc3c9c834b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -33,6 +33,7 @@ import android.media.IVolumeController;
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
@@ -82,6 +83,8 @@ interface IAudioService {
int getLastAudibleStreamVolume(int streamType);
+ AudioProductStrategies getAudioProductStrategies();
+
void setMicrophoneMute(boolean on, String callingPackage, int userId);
void setRingerModeExternal(int ringerMode, String caller);
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 445edd1da8f1..5f65d586b730 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -364,11 +364,10 @@ public class AudioPolicy {
* played.
* @param uid UID of the application to affect.
* @param devices list of devices to which the audio stream of the application may be routed.
- * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
- * otherwise.
+ * @return true if the change was successful, false otherwise.
*/
@SystemApi
- public int setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
+ public boolean setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
if (devices == null) {
throw new IllegalArgumentException("Illegal null list of audio devices");
}
@@ -393,10 +392,10 @@ public class AudioPolicy {
try {
final int status = service.setUidDeviceAffinity(this.cb(),
uid, deviceTypes, deviceAdresses);
- return status;
+ return (status == AudioManager.SUCCESS);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setUidDeviceAffinity", e);
- return AudioManager.ERROR;
+ return false;
}
}
}
@@ -406,11 +405,10 @@ public class AudioPolicy {
* Removes audio device affinity previously set by
* {@link #setUidDeviceAffinity(int, java.util.List)}.
* @param uid UID of the application affected.
- * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
- * otherwise.
+ * @return true if the change was successful, false otherwise.
*/
@SystemApi
- public int removeUidDeviceAffinity(int uid) {
+ public boolean removeUidDeviceAffinity(int uid) {
synchronized (mLock) {
if (mStatus != POLICY_STATUS_REGISTERED) {
throw new IllegalStateException("Cannot use unregistered AudioPolicy");
@@ -418,10 +416,10 @@ public class AudioPolicy {
final IAudioService service = getService();
try {
final int status = service.removeUidDeviceAffinity(this.cb(), uid);
- return status;
+ return (status == AudioManager.SUCCESS);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in removeUidDeviceAffinity", e);
- return AudioManager.ERROR;
+ return false;
}
}
}
@@ -682,7 +680,6 @@ public class AudioPolicy {
*
*/
public static abstract class AudioPolicyVolumeCallback {
- /** @hide */
public AudioPolicyVolumeCallback() {}
/**
* Called when volume key-related changes are triggered, on the key down event.
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.java b/media/java/android/media/audiopolicy/AudioProductStrategies.java
index b8364091ff12..6a2375fe153d 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategies.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategies.java
@@ -144,8 +144,10 @@ public final class AudioProductStrategies implements Iterable<AudioProductStrate
* @hide
* @param aa the {@link AudioAttributes} for which stream type is requested
* @return the legacy stream type relevant for the given {@link AudioAttributes}.
- * If the product strategy is not associated to any stream, it returns STREAM_MUSIC.
- * If no product strategy supports the stream type, it returns STREAM_MUSIC.
+ * If the product strategy is not associated to any stream, it returns
+ * {@link AudioSystem#STREAM_MUSIC}.
+ * If no product strategy supports the stream type, it returns
+ * {@link AudioSystem#STREAM_MUSIC}.
*/
@SystemApi
public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) {
@@ -165,6 +167,19 @@ public final class AudioProductStrategies implements Iterable<AudioProductStrate
return AudioSystem.STREAM_MUSIC;
}
+ /**
+ * @hide
+ * @param aa the {@link AudioAttributes} to be considered
+ * @return {@link AudioProductStrategy} supporting the given {@link AudioAttributes}.
+ * null is returned if no match with given attributes.
+ */
+ @SystemApi
+ @Nullable
+ public AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull AudioAttributes aa) {
+ Preconditions.checkNotNull(aa, "attributes must not be null");
+ return getById(native_get_product_strategies_from_audio_attributes(aa));
+ }
+
@Override
public int describeContents() {
return 0;
@@ -198,4 +213,7 @@ public final class AudioProductStrategies implements Iterable<AudioProductStrate
private static native int native_list_audio_product_strategies(
ArrayList<AudioProductStrategy> strategies);
+
+ private static native int native_get_product_strategies_from_audio_attributes(
+ AudioAttributes attributes);
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 8ed265d674a6..65b58ab6bfef 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -20,8 +20,8 @@ cc_library_shared {
"android_media_MediaScanner.cpp",
"android_media_MediaSync.cpp",
"android_media_ResampleInputStream.cpp",
+ "android_media_Streams.cpp",
"android_media_SyncParams.cpp",
- "android_media_Utils.cpp",
"android_mtp_MtpDatabase.cpp",
"android_mtp_MtpDevice.cpp",
"android_mtp_MtpServer.cpp",
@@ -34,6 +34,7 @@ cc_library_shared {
"libutils",
"libbinder",
"libmedia",
+ "libmedia_jni_utils",
"libmedia_omx",
"libmediametrics",
"libmediadrm",
@@ -85,6 +86,36 @@ cc_library_shared {
}
cc_library_shared {
+ name: "libmedia_jni_utils",
+ srcs: [
+ "android_media_Utils.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmedia_omx",
+ "libnativewindow",
+ "libui",
+ "libutils",
+ "android.hidl.token@1.0-utils",
+ ],
+
+ include_dirs: [
+ "system/media/camera/include",
+ ],
+
+ export_include_dirs: ["."],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
+
+cc_library_shared {
name: "libmedia2_jni",
srcs: [
@@ -125,7 +156,6 @@ cc_library_shared {
"libcrypto",
"libcutils",
"libjsoncpp",
- "libmedia_helper",
"libmedia_player2_util",
"libmediaplayer2",
"libmediaplayer2-protos",
@@ -133,7 +163,6 @@ cc_library_shared {
"libmediautils",
"libprocessgroup",
"libprotobuf-cpp-lite",
- "libstagefright",
"libstagefright_esds",
"libstagefright_foundation_without_imemory",
"libstagefright_httplive",
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f07f1e8fb62b..150b6f918685 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -23,7 +23,7 @@
#include "android_media_MediaCrypto.h"
#include "android_media_MediaDescrambler.h"
#include "android_media_MediaMetricsJNI.h"
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
#include "android_util_Binder.h"
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 6b8f7457eab9..923d1d253c6e 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -31,7 +31,7 @@
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
using namespace android;
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index c6b171bdd6d4..f5ae9d0d5d2f 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -22,7 +22,7 @@
#include "android_media_MediaDataSource.h"
#include "android_media_MediaExtractor.h"
#include "android_media_MediaMetricsJNI.h"
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "android_os_HwRemoteBinder.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index c1226fa89fe4..a4807843d7d8 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaMetadataRetrieverJNI"
+#include <cmath>
#include <assert.h>
#include <utils/Log.h>
#include <utils/threads.h>
@@ -32,7 +33,7 @@
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_media_MediaDataSource.h"
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "android_util_Binder.h"
#include "android/graphics/GraphicsJNI.h"
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index f11452a9d80d..f0aa4c3f1ab6 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "MediaMuxer-JNI"
#include <utils/Log.h>
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 35b10817c05c..d24edc7552ae 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -44,7 +44,7 @@
#include "android_media_PlaybackParams.h"
#include "android_media_SyncParams.h"
#include "android_media_VolumeShaper.h"
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
new file mode 100644
index 000000000000..b7cbd97409a2
--- /dev/null
+++ b/media/jni/android_media_Streams.cpp
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "AndroidMediaStreams"
+
+#include <utils/Log.h>
+#include "android_media_Streams.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+AssetStream::AssetStream(SkStream* stream)
+ : mStream(stream), mPosition(0) {
+}
+
+AssetStream::~AssetStream() {
+}
+
+piex::Error AssetStream::GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) {
+ // Seek first.
+ if (mPosition != offset) {
+ if (!mStream->seek(offset)) {
+ return piex::Error::kFail;
+ }
+ }
+
+ // Read bytes.
+ size_t size = mStream->read((void*)data, length);
+ mPosition = offset + size;
+
+ return size == length ? piex::Error::kOk : piex::Error::kFail;
+}
+
+BufferedStream::BufferedStream(SkStream* stream)
+ : mStream(stream) {
+}
+
+BufferedStream::~BufferedStream() {
+}
+
+piex::Error BufferedStream::GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) {
+ // Seek first.
+ if (offset + length > mStreamBuffer.bytesWritten()) {
+ size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
+ if (sizeToRead <= kMinSizeToRead) {
+ sizeToRead = kMinSizeToRead;
+ }
+
+ void* tempBuffer = malloc(sizeToRead);
+ if (tempBuffer == NULL) {
+ return piex::Error::kFail;
+ }
+
+ size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
+ if (bytesRead != sizeToRead) {
+ free(tempBuffer);
+ return piex::Error::kFail;
+ }
+ mStreamBuffer.write(tempBuffer, bytesRead);
+ free(tempBuffer);
+ }
+
+ // Read bytes.
+ if (mStreamBuffer.read((void*)data, offset, length)) {
+ return piex::Error::kOk;
+ } else {
+ return piex::Error::kFail;
+ }
+}
+
+FileStream::FileStream(const int fd)
+ : mPosition(0) {
+ mFile = fdopen(fd, "r");
+ if (mFile == NULL) {
+ return;
+ }
+}
+
+FileStream::FileStream(const String8 filename)
+ : mPosition(0) {
+ mFile = fopen(filename.string(), "r");
+ if (mFile == NULL) {
+ return;
+ }
+}
+
+FileStream::~FileStream() {
+ if (mFile != NULL) {
+ fclose(mFile);
+ mFile = NULL;
+ }
+}
+
+piex::Error FileStream::GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) {
+ if (mFile == NULL) {
+ return piex::Error::kFail;
+ }
+
+ // Seek first.
+ if (mPosition != offset) {
+ fseek(mFile, offset, SEEK_SET);
+ }
+
+ // Read bytes.
+ size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile);
+ mPosition += size;
+
+ // Handle errors and verify the size.
+ if (ferror(mFile) || size != length) {
+ ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
+ return piex::Error::kFail;
+ }
+ return piex::Error::kOk;
+}
+
+bool FileStream::exists() const {
+ return mFile != NULL;
+}
+
+bool GetExifFromRawImage(
+ piex::StreamInterface* stream, const String8& filename,
+ piex::PreviewImageData& image_data) {
+ // Reset the PreviewImageData to its default.
+ image_data = piex::PreviewImageData();
+
+ if (!piex::IsRaw(stream)) {
+ // Format not supported.
+ ALOGV("Format not supported: %s", filename.string());
+ return false;
+ }
+
+ piex::Error err = piex::GetPreviewImageData(stream, &image_data);
+
+ if (err != piex::Error::kOk) {
+ // The input data seems to be broken.
+ ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err);
+ return false;
+ }
+
+ return true;
+}
+
+bool ConvertKeyValueArraysToKeyedVector(
+ JNIEnv *env, jobjectArray keys, jobjectArray values,
+ KeyedVector<String8, String8>* keyedVector) {
+
+ int nKeyValuePairs = 0;
+ bool failed = false;
+ if (keys != NULL && values != NULL) {
+ nKeyValuePairs = env->GetArrayLength(keys);
+ failed = (nKeyValuePairs != env->GetArrayLength(values));
+ }
+
+ if (!failed) {
+ failed = ((keys != NULL && values == NULL) ||
+ (keys == NULL && values != NULL));
+ }
+
+ if (failed) {
+ ALOGE("keys and values arrays have different length");
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return false;
+ }
+
+ for (int i = 0; i < nKeyValuePairs; ++i) {
+ // No need to check on the ArrayIndexOutOfBoundsException, since
+ // it won't happen here.
+ jstring key = (jstring) env->GetObjectArrayElement(keys, i);
+ jstring value = (jstring) env->GetObjectArrayElement(values, i);
+
+ const char* keyStr = env->GetStringUTFChars(key, NULL);
+ if (!keyStr) { // OutOfMemoryError
+ return false;
+ }
+
+ const char* valueStr = env->GetStringUTFChars(value, NULL);
+ if (!valueStr) { // OutOfMemoryError
+ env->ReleaseStringUTFChars(key, keyStr);
+ return false;
+ }
+
+ keyedVector->add(String8(keyStr), String8(valueStr));
+
+ env->ReleaseStringUTFChars(key, keyStr);
+ env->ReleaseStringUTFChars(value, valueStr);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(value);
+ }
+ return true;
+}
+
+static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
+ ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer"));
+ CHECK(clazz.get() != NULL);
+
+ jmethodID integerConstructID =
+ env->GetMethodID(clazz.get(), "<init>", "(I)V");
+ CHECK(integerConstructID != NULL);
+
+ return env->NewObject(clazz.get(), integerConstructID, value);
+}
+
+static jobject makeLongObject(JNIEnv *env, int64_t value) {
+ ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long"));
+ CHECK(clazz.get() != NULL);
+
+ jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V");
+ CHECK(longConstructID != NULL);
+
+ return env->NewObject(clazz.get(), longConstructID, value);
+}
+
+static jobject makeFloatObject(JNIEnv *env, float value) {
+ ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float"));
+ CHECK(clazz.get() != NULL);
+
+ jmethodID floatConstructID =
+ env->GetMethodID(clazz.get(), "<init>", "(F)V");
+ CHECK(floatConstructID != NULL);
+
+ return env->NewObject(clazz.get(), floatConstructID, value);
+}
+
+static jobject makeByteBufferObject(
+ JNIEnv *env, const void *data, size_t size) {
+ jbyteArray byteArrayObj = env->NewByteArray(size);
+ env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
+
+ ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer"));
+ CHECK(clazz.get() != NULL);
+
+ jmethodID byteBufWrapID =
+ env->GetStaticMethodID(
+ clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;");
+ CHECK(byteBufWrapID != NULL);
+
+ jobject byteBufObj = env->CallStaticObjectMethod(
+ clazz.get(), byteBufWrapID, byteArrayObj);
+
+ env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
+
+ return byteBufObj;
+}
+
+static void SetMapInt32(
+ JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID,
+ const char *key, int32_t value) {
+ jstring keyObj = env->NewStringUTF(key);
+ jobject valueObj = makeIntegerObject(env, value);
+
+ env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj);
+
+ env->DeleteLocalRef(valueObj); valueObj = NULL;
+ env->DeleteLocalRef(keyObj); keyObj = NULL;
+}
+
+status_t ConvertMessageToMap(
+ JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
+ ScopedLocalRef<jclass> hashMapClazz(
+ env, env->FindClass("java/util/HashMap"));
+
+ if (hashMapClazz.get() == NULL) {
+ return -EINVAL;
+ }
+
+ jmethodID hashMapConstructID =
+ env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
+
+ if (hashMapConstructID == NULL) {
+ return -EINVAL;
+ }
+
+ jmethodID hashMapPutID =
+ env->GetMethodID(
+ hashMapClazz.get(),
+ "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+ if (hashMapPutID == NULL) {
+ return -EINVAL;
+ }
+
+ jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
+
+ for (size_t i = 0; i < msg->countEntries(); ++i) {
+ AMessage::Type valueType;
+ const char *key = msg->getEntryNameAt(i, &valueType);
+
+ if (!strncmp(key, "android._", 9)) {
+ // don't expose private keys (starting with android._)
+ continue;
+ }
+
+ jobject valueObj = NULL;
+
+ switch (valueType) {
+ case AMessage::kTypeInt32:
+ {
+ int32_t val;
+ CHECK(msg->findInt32(key, &val));
+
+ valueObj = makeIntegerObject(env, val);
+ break;
+ }
+
+ case AMessage::kTypeInt64:
+ {
+ int64_t val;
+ CHECK(msg->findInt64(key, &val));
+
+ valueObj = makeLongObject(env, val);
+ break;
+ }
+
+ case AMessage::kTypeFloat:
+ {
+ float val;
+ CHECK(msg->findFloat(key, &val));
+
+ valueObj = makeFloatObject(env, val);
+ break;
+ }
+
+ case AMessage::kTypeString:
+ {
+ AString val;
+ CHECK(msg->findString(key, &val));
+
+ valueObj = env->NewStringUTF(val.c_str());
+ break;
+ }
+
+ case AMessage::kTypeBuffer:
+ {
+ sp<ABuffer> buffer;
+ CHECK(msg->findBuffer(key, &buffer));
+
+ valueObj = makeByteBufferObject(
+ env, buffer->data(), buffer->size());
+ break;
+ }
+
+ case AMessage::kTypeRect:
+ {
+ int32_t left, top, right, bottom;
+ CHECK(msg->findRect(key, &left, &top, &right, &bottom));
+
+ SetMapInt32(
+ env,
+ hashMap,
+ hashMapPutID,
+ AStringPrintf("%s-left", key).c_str(),
+ left);
+
+ SetMapInt32(
+ env,
+ hashMap,
+ hashMapPutID,
+ AStringPrintf("%s-top", key).c_str(),
+ top);
+
+ SetMapInt32(
+ env,
+ hashMap,
+ hashMapPutID,
+ AStringPrintf("%s-right", key).c_str(),
+ right);
+
+ SetMapInt32(
+ env,
+ hashMap,
+ hashMapPutID,
+ AStringPrintf("%s-bottom", key).c_str(),
+ bottom);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (valueObj != NULL) {
+ jstring keyObj = env->NewStringUTF(key);
+
+ env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);
+
+ env->DeleteLocalRef(keyObj); keyObj = NULL;
+ env->DeleteLocalRef(valueObj); valueObj = NULL;
+ }
+ }
+
+ *map = hashMap;
+
+ return OK;
+}
+
+status_t ConvertKeyValueArraysToMessage(
+ JNIEnv *env, jobjectArray keys, jobjectArray values,
+ sp<AMessage> *out) {
+ ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
+ CHECK(stringClass.get() != NULL);
+ ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer"));
+ CHECK(integerClass.get() != NULL);
+ ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
+ CHECK(longClass.get() != NULL);
+ ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float"));
+ CHECK(floatClass.get() != NULL);
+ ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
+ CHECK(byteBufClass.get() != NULL);
+
+ sp<AMessage> msg = new AMessage;
+
+ jsize numEntries = 0;
+
+ if (keys != NULL) {
+ if (values == NULL) {
+ return -EINVAL;
+ }
+
+ numEntries = env->GetArrayLength(keys);
+
+ if (numEntries != env->GetArrayLength(values)) {
+ return -EINVAL;
+ }
+ } else if (values != NULL) {
+ return -EINVAL;
+ }
+
+ for (jsize i = 0; i < numEntries; ++i) {
+ jobject keyObj = env->GetObjectArrayElement(keys, i);
+
+ if (!env->IsInstanceOf(keyObj, stringClass.get())) {
+ return -EINVAL;
+ }
+
+ const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL);
+
+ if (tmp == NULL) {
+ return -ENOMEM;
+ }
+
+ AString key = tmp;
+
+ env->ReleaseStringUTFChars((jstring)keyObj, tmp);
+ tmp = NULL;
+
+ if (key.startsWith("android._")) {
+ // don't propagate private keys (starting with android._)
+ continue;
+ }
+
+ jobject valueObj = env->GetObjectArrayElement(values, i);
+
+ if (env->IsInstanceOf(valueObj, stringClass.get())) {
+ const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
+
+ if (value == NULL) {
+ return -ENOMEM;
+ }
+
+ msg->setString(key.c_str(), value);
+
+ env->ReleaseStringUTFChars((jstring)valueObj, value);
+ value = NULL;
+ } else if (env->IsInstanceOf(valueObj, integerClass.get())) {
+ jmethodID intValueID =
+ env->GetMethodID(integerClass.get(), "intValue", "()I");
+ CHECK(intValueID != NULL);
+
+ jint value = env->CallIntMethod(valueObj, intValueID);
+
+ msg->setInt32(key.c_str(), value);
+ } else if (env->IsInstanceOf(valueObj, longClass.get())) {
+ jmethodID longValueID =
+ env->GetMethodID(longClass.get(), "longValue", "()J");
+ CHECK(longValueID != NULL);
+
+ jlong value = env->CallLongMethod(valueObj, longValueID);
+
+ msg->setInt64(key.c_str(), value);
+ } else if (env->IsInstanceOf(valueObj, floatClass.get())) {
+ jmethodID floatValueID =
+ env->GetMethodID(floatClass.get(), "floatValue", "()F");
+ CHECK(floatValueID != NULL);
+
+ jfloat value = env->CallFloatMethod(valueObj, floatValueID);
+
+ msg->setFloat(key.c_str(), value);
+ } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) {
+ jmethodID positionID =
+ env->GetMethodID(byteBufClass.get(), "position", "()I");
+ CHECK(positionID != NULL);
+
+ jmethodID limitID =
+ env->GetMethodID(byteBufClass.get(), "limit", "()I");
+ CHECK(limitID != NULL);
+
+ jint position = env->CallIntMethod(valueObj, positionID);
+ jint limit = env->CallIntMethod(valueObj, limitID);
+
+ sp<ABuffer> buffer = new ABuffer(limit - position);
+
+ void *data = env->GetDirectBufferAddress(valueObj);
+
+ if (data != NULL) {
+ memcpy(buffer->data(),
+ (const uint8_t *)data + position,
+ buffer->size());
+ } else {
+ jmethodID arrayID =
+ env->GetMethodID(byteBufClass.get(), "array", "()[B");
+ CHECK(arrayID != NULL);
+
+ jbyteArray byteArray =
+ (jbyteArray)env->CallObjectMethod(valueObj, arrayID);
+ CHECK(byteArray != NULL);
+
+ env->GetByteArrayRegion(
+ byteArray,
+ position,
+ buffer->size(),
+ (jbyte *)buffer->data());
+
+ env->DeleteLocalRef(byteArray); byteArray = NULL;
+ }
+
+ msg->setBuffer(key.c_str(), buffer);
+ }
+ }
+
+ *out = msg;
+
+ return OK;
+}
+
+} // namespace android
+
diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h
new file mode 100644
index 000000000000..d174f9a6650c
--- /dev/null
+++ b/media/jni/android_media_Streams.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_STREAMS_H_
+#define _ANDROID_MEDIA_STREAMS_H_
+
+#include "src/piex_types.h"
+#include "src/piex.h"
+
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <SkStream.h>
+
+
+namespace android {
+
+class AssetStream : public piex::StreamInterface {
+private:
+ SkStream *mStream;
+ size_t mPosition;
+
+public:
+ explicit AssetStream(SkStream* stream);
+ ~AssetStream();
+
+ // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+ // provided by the caller, guaranteed to be at least "length" bytes long.
+ // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+ // 'offset' bytes from the start of the stream.
+ // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+ // change the contents of 'data'.
+ piex::Error GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
+class BufferedStream : public piex::StreamInterface {
+private:
+ SkStream *mStream;
+ // Growable memory stream
+ SkDynamicMemoryWStream mStreamBuffer;
+
+ // Minimum size to read on filling the buffer.
+ const size_t kMinSizeToRead = 8192;
+
+public:
+ explicit BufferedStream(SkStream* stream);
+ ~BufferedStream();
+
+ // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+ // provided by the caller, guaranteed to be at least "length" bytes long.
+ // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+ // 'offset' bytes from the start of the stream.
+ // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+ // change the contents of 'data'.
+ piex::Error GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
+class FileStream : public piex::StreamInterface {
+private:
+ FILE *mFile;
+ size_t mPosition;
+
+public:
+ explicit FileStream(const int fd);
+ explicit FileStream(const String8 filename);
+ ~FileStream();
+
+ // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+ // provided by the caller, guaranteed to be at least "length" bytes long.
+ // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+ // 'offset' bytes from the start of the stream.
+ // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+ // change the contents of 'data'.
+ piex::Error GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) override;
+ bool exists() const;
+};
+
+// Reads EXIF metadata from a given raw image via piex.
+// And returns true if the operation is successful; otherwise, false.
+bool GetExifFromRawImage(
+ piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data);
+
+// Returns true if the conversion is successful; otherwise, false.
+bool ConvertKeyValueArraysToKeyedVector(
+ JNIEnv *env, jobjectArray keys, jobjectArray values,
+ KeyedVector<String8, String8>* vector);
+
+struct AMessage;
+status_t ConvertMessageToMap(
+ JNIEnv *env, const sp<AMessage> &msg, jobject *map);
+
+status_t ConvertKeyValueArraysToMessage(
+ JNIEnv *env, jobjectArray keys, jobjectArray values,
+ sp<AMessage> *msg);
+
+}; // namespace android
+
+#endif // _ANDROID_MEDIA_STREAMS_H_
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 01baadb2f024..2ef7b9e22b84 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -21,12 +21,6 @@
#include <utils/Log.h>
#include "android_media_Utils.h"
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <nativehelper/ScopedLocalRef.h>
-
#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
// Must be in sync with the value in HeicCompositeStream.cpp
@@ -34,533 +28,6 @@
namespace android {
-AssetStream::AssetStream(SkStream* stream)
- : mStream(stream), mPosition(0) {
-}
-
-AssetStream::~AssetStream() {
-}
-
-piex::Error AssetStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (mPosition != offset) {
- if (!mStream->seek(offset)) {
- return piex::Error::kFail;
- }
- }
-
- // Read bytes.
- size_t size = mStream->read((void*)data, length);
- mPosition = offset + size;
-
- return size == length ? piex::Error::kOk : piex::Error::kFail;
-}
-
-BufferedStream::BufferedStream(SkStream* stream)
- : mStream(stream) {
-}
-
-BufferedStream::~BufferedStream() {
-}
-
-piex::Error BufferedStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (offset + length > mStreamBuffer.bytesWritten()) {
- size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
- if (sizeToRead <= kMinSizeToRead) {
- sizeToRead = kMinSizeToRead;
- }
-
- void* tempBuffer = malloc(sizeToRead);
- if (tempBuffer == NULL) {
- return piex::Error::kFail;
- }
-
- size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
- if (bytesRead != sizeToRead) {
- free(tempBuffer);
- return piex::Error::kFail;
- }
- mStreamBuffer.write(tempBuffer, bytesRead);
- free(tempBuffer);
- }
-
- // Read bytes.
- if (mStreamBuffer.read((void*)data, offset, length)) {
- return piex::Error::kOk;
- } else {
- return piex::Error::kFail;
- }
-}
-
-FileStream::FileStream(const int fd)
- : mPosition(0) {
- mFile = fdopen(fd, "r");
- if (mFile == NULL) {
- return;
- }
-}
-
-FileStream::FileStream(const String8 filename)
- : mPosition(0) {
- mFile = fopen(filename.string(), "r");
- if (mFile == NULL) {
- return;
- }
-}
-
-FileStream::~FileStream() {
- if (mFile != NULL) {
- fclose(mFile);
- mFile = NULL;
- }
-}
-
-piex::Error FileStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- if (mFile == NULL) {
- return piex::Error::kFail;
- }
-
- // Seek first.
- if (mPosition != offset) {
- fseek(mFile, offset, SEEK_SET);
- }
-
- // Read bytes.
- size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile);
- mPosition += size;
-
- // Handle errors and verify the size.
- if (ferror(mFile) || size != length) {
- ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
- return piex::Error::kFail;
- }
- return piex::Error::kOk;
-}
-
-bool FileStream::exists() const {
- return mFile != NULL;
-}
-
-bool GetExifFromRawImage(
- piex::StreamInterface* stream, const String8& filename,
- piex::PreviewImageData& image_data) {
- // Reset the PreviewImageData to its default.
- image_data = piex::PreviewImageData();
-
- if (!piex::IsRaw(stream)) {
- // Format not supported.
- ALOGV("Format not supported: %s", filename.string());
- return false;
- }
-
- piex::Error err = piex::GetPreviewImageData(stream, &image_data);
-
- if (err != piex::Error::kOk) {
- // The input data seems to be broken.
- ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err);
- return false;
- }
-
- return true;
-}
-
-bool ConvertKeyValueArraysToKeyedVector(
- JNIEnv *env, jobjectArray keys, jobjectArray values,
- KeyedVector<String8, String8>* keyedVector) {
-
- int nKeyValuePairs = 0;
- bool failed = false;
- if (keys != NULL && values != NULL) {
- nKeyValuePairs = env->GetArrayLength(keys);
- failed = (nKeyValuePairs != env->GetArrayLength(values));
- }
-
- if (!failed) {
- failed = ((keys != NULL && values == NULL) ||
- (keys == NULL && values != NULL));
- }
-
- if (failed) {
- ALOGE("keys and values arrays have different length");
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return false;
- }
-
- for (int i = 0; i < nKeyValuePairs; ++i) {
- // No need to check on the ArrayIndexOutOfBoundsException, since
- // it won't happen here.
- jstring key = (jstring) env->GetObjectArrayElement(keys, i);
- jstring value = (jstring) env->GetObjectArrayElement(values, i);
-
- const char* keyStr = env->GetStringUTFChars(key, NULL);
- if (!keyStr) { // OutOfMemoryError
- return false;
- }
-
- const char* valueStr = env->GetStringUTFChars(value, NULL);
- if (!valueStr) { // OutOfMemoryError
- env->ReleaseStringUTFChars(key, keyStr);
- return false;
- }
-
- keyedVector->add(String8(keyStr), String8(valueStr));
-
- env->ReleaseStringUTFChars(key, keyStr);
- env->ReleaseStringUTFChars(value, valueStr);
- env->DeleteLocalRef(key);
- env->DeleteLocalRef(value);
- }
- return true;
-}
-
-static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
- ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer"));
- CHECK(clazz.get() != NULL);
-
- jmethodID integerConstructID =
- env->GetMethodID(clazz.get(), "<init>", "(I)V");
- CHECK(integerConstructID != NULL);
-
- return env->NewObject(clazz.get(), integerConstructID, value);
-}
-
-static jobject makeLongObject(JNIEnv *env, int64_t value) {
- ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long"));
- CHECK(clazz.get() != NULL);
-
- jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V");
- CHECK(longConstructID != NULL);
-
- return env->NewObject(clazz.get(), longConstructID, value);
-}
-
-static jobject makeFloatObject(JNIEnv *env, float value) {
- ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float"));
- CHECK(clazz.get() != NULL);
-
- jmethodID floatConstructID =
- env->GetMethodID(clazz.get(), "<init>", "(F)V");
- CHECK(floatConstructID != NULL);
-
- return env->NewObject(clazz.get(), floatConstructID, value);
-}
-
-static jobject makeByteBufferObject(
- JNIEnv *env, const void *data, size_t size) {
- jbyteArray byteArrayObj = env->NewByteArray(size);
- env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
-
- ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer"));
- CHECK(clazz.get() != NULL);
-
- jmethodID byteBufWrapID =
- env->GetStaticMethodID(
- clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;");
- CHECK(byteBufWrapID != NULL);
-
- jobject byteBufObj = env->CallStaticObjectMethod(
- clazz.get(), byteBufWrapID, byteArrayObj);
-
- env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
-
- return byteBufObj;
-}
-
-static void SetMapInt32(
- JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID,
- const char *key, int32_t value) {
- jstring keyObj = env->NewStringUTF(key);
- jobject valueObj = makeIntegerObject(env, value);
-
- env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj);
-
- env->DeleteLocalRef(valueObj); valueObj = NULL;
- env->DeleteLocalRef(keyObj); keyObj = NULL;
-}
-
-status_t ConvertMessageToMap(
- JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
- ScopedLocalRef<jclass> hashMapClazz(
- env, env->FindClass("java/util/HashMap"));
-
- if (hashMapClazz.get() == NULL) {
- return -EINVAL;
- }
-
- jmethodID hashMapConstructID =
- env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
-
- if (hashMapConstructID == NULL) {
- return -EINVAL;
- }
-
- jmethodID hashMapPutID =
- env->GetMethodID(
- hashMapClazz.get(),
- "put",
- "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-
- if (hashMapPutID == NULL) {
- return -EINVAL;
- }
-
- jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
-
- for (size_t i = 0; i < msg->countEntries(); ++i) {
- AMessage::Type valueType;
- const char *key = msg->getEntryNameAt(i, &valueType);
-
- if (!strncmp(key, "android._", 9)) {
- // don't expose private keys (starting with android._)
- continue;
- }
-
- jobject valueObj = NULL;
-
- switch (valueType) {
- case AMessage::kTypeInt32:
- {
- int32_t val;
- CHECK(msg->findInt32(key, &val));
-
- valueObj = makeIntegerObject(env, val);
- break;
- }
-
- case AMessage::kTypeInt64:
- {
- int64_t val;
- CHECK(msg->findInt64(key, &val));
-
- valueObj = makeLongObject(env, val);
- break;
- }
-
- case AMessage::kTypeFloat:
- {
- float val;
- CHECK(msg->findFloat(key, &val));
-
- valueObj = makeFloatObject(env, val);
- break;
- }
-
- case AMessage::kTypeString:
- {
- AString val;
- CHECK(msg->findString(key, &val));
-
- valueObj = env->NewStringUTF(val.c_str());
- break;
- }
-
- case AMessage::kTypeBuffer:
- {
- sp<ABuffer> buffer;
- CHECK(msg->findBuffer(key, &buffer));
-
- valueObj = makeByteBufferObject(
- env, buffer->data(), buffer->size());
- break;
- }
-
- case AMessage::kTypeRect:
- {
- int32_t left, top, right, bottom;
- CHECK(msg->findRect(key, &left, &top, &right, &bottom));
-
- SetMapInt32(
- env,
- hashMap,
- hashMapPutID,
- AStringPrintf("%s-left", key).c_str(),
- left);
-
- SetMapInt32(
- env,
- hashMap,
- hashMapPutID,
- AStringPrintf("%s-top", key).c_str(),
- top);
-
- SetMapInt32(
- env,
- hashMap,
- hashMapPutID,
- AStringPrintf("%s-right", key).c_str(),
- right);
-
- SetMapInt32(
- env,
- hashMap,
- hashMapPutID,
- AStringPrintf("%s-bottom", key).c_str(),
- bottom);
- break;
- }
-
- default:
- break;
- }
-
- if (valueObj != NULL) {
- jstring keyObj = env->NewStringUTF(key);
-
- env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);
-
- env->DeleteLocalRef(keyObj); keyObj = NULL;
- env->DeleteLocalRef(valueObj); valueObj = NULL;
- }
- }
-
- *map = hashMap;
-
- return OK;
-}
-
-status_t ConvertKeyValueArraysToMessage(
- JNIEnv *env, jobjectArray keys, jobjectArray values,
- sp<AMessage> *out) {
- ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
- CHECK(stringClass.get() != NULL);
- ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer"));
- CHECK(integerClass.get() != NULL);
- ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
- CHECK(longClass.get() != NULL);
- ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float"));
- CHECK(floatClass.get() != NULL);
- ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
- CHECK(byteBufClass.get() != NULL);
-
- sp<AMessage> msg = new AMessage;
-
- jsize numEntries = 0;
-
- if (keys != NULL) {
- if (values == NULL) {
- return -EINVAL;
- }
-
- numEntries = env->GetArrayLength(keys);
-
- if (numEntries != env->GetArrayLength(values)) {
- return -EINVAL;
- }
- } else if (values != NULL) {
- return -EINVAL;
- }
-
- for (jsize i = 0; i < numEntries; ++i) {
- jobject keyObj = env->GetObjectArrayElement(keys, i);
-
- if (!env->IsInstanceOf(keyObj, stringClass.get())) {
- return -EINVAL;
- }
-
- const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL);
-
- if (tmp == NULL) {
- return -ENOMEM;
- }
-
- AString key = tmp;
-
- env->ReleaseStringUTFChars((jstring)keyObj, tmp);
- tmp = NULL;
-
- if (key.startsWith("android._")) {
- // don't propagate private keys (starting with android._)
- continue;
- }
-
- jobject valueObj = env->GetObjectArrayElement(values, i);
-
- if (env->IsInstanceOf(valueObj, stringClass.get())) {
- const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
-
- if (value == NULL) {
- return -ENOMEM;
- }
-
- msg->setString(key.c_str(), value);
-
- env->ReleaseStringUTFChars((jstring)valueObj, value);
- value = NULL;
- } else if (env->IsInstanceOf(valueObj, integerClass.get())) {
- jmethodID intValueID =
- env->GetMethodID(integerClass.get(), "intValue", "()I");
- CHECK(intValueID != NULL);
-
- jint value = env->CallIntMethod(valueObj, intValueID);
-
- msg->setInt32(key.c_str(), value);
- } else if (env->IsInstanceOf(valueObj, longClass.get())) {
- jmethodID longValueID =
- env->GetMethodID(longClass.get(), "longValue", "()J");
- CHECK(longValueID != NULL);
-
- jlong value = env->CallLongMethod(valueObj, longValueID);
-
- msg->setInt64(key.c_str(), value);
- } else if (env->IsInstanceOf(valueObj, floatClass.get())) {
- jmethodID floatValueID =
- env->GetMethodID(floatClass.get(), "floatValue", "()F");
- CHECK(floatValueID != NULL);
-
- jfloat value = env->CallFloatMethod(valueObj, floatValueID);
-
- msg->setFloat(key.c_str(), value);
- } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) {
- jmethodID positionID =
- env->GetMethodID(byteBufClass.get(), "position", "()I");
- CHECK(positionID != NULL);
-
- jmethodID limitID =
- env->GetMethodID(byteBufClass.get(), "limit", "()I");
- CHECK(limitID != NULL);
-
- jint position = env->CallIntMethod(valueObj, positionID);
- jint limit = env->CallIntMethod(valueObj, limitID);
-
- sp<ABuffer> buffer = new ABuffer(limit - position);
-
- void *data = env->GetDirectBufferAddress(valueObj);
-
- if (data != NULL) {
- memcpy(buffer->data(),
- (const uint8_t *)data + position,
- buffer->size());
- } else {
- jmethodID arrayID =
- env->GetMethodID(byteBufClass.get(), "array", "()[B");
- CHECK(arrayID != NULL);
-
- jbyteArray byteArray =
- (jbyteArray)env->CallObjectMethod(valueObj, arrayID);
- CHECK(byteArray != NULL);
-
- env->GetByteArrayRegion(
- byteArray,
- position,
- buffer->size(),
- (jbyte *)buffer->data());
-
- env->DeleteLocalRef(byteArray); byteArray = NULL;
- }
-
- msg->setBuffer(key.c_str(), buffer);
- }
- }
-
- *out = msg;
-
- return OK;
-}
-
// -----------Utility functions used by ImageReader/Writer JNI-----------------
enum {
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 19c1b88f78e8..12841c097943 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -17,100 +17,10 @@
#ifndef _ANDROID_MEDIA_UTILS_H_
#define _ANDROID_MEDIA_UTILS_H_
-#include "src/piex_types.h"
-#include "src/piex.h"
-
-#include <android_runtime/AndroidRuntime.h>
#include <gui/CpuConsumer.h>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <SkStream.h>
namespace android {
-class AssetStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- size_t mPosition;
-
-public:
- explicit AssetStream(SkStream* stream);
- ~AssetStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class BufferedStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- // Growable memory stream
- SkDynamicMemoryWStream mStreamBuffer;
-
- // Minimum size to read on filling the buffer.
- const size_t kMinSizeToRead = 8192;
-
-public:
- explicit BufferedStream(SkStream* stream);
- ~BufferedStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class FileStream : public piex::StreamInterface {
-private:
- FILE *mFile;
- size_t mPosition;
-
-public:
- explicit FileStream(const int fd);
- explicit FileStream(const String8 filename);
- ~FileStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
- bool exists() const;
-};
-
-// Reads EXIF metadata from a given raw image via piex.
-// And returns true if the operation is successful; otherwise, false.
-bool GetExifFromRawImage(
- piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data);
-
-// Returns true if the conversion is successful; otherwise, false.
-bool ConvertKeyValueArraysToKeyedVector(
- JNIEnv *env, jobjectArray keys, jobjectArray values,
- KeyedVector<String8, String8>* vector);
-
-struct AMessage;
-status_t ConvertMessageToMap(
- JNIEnv *env, const sp<AMessage> &msg, jobject *map);
-
-status_t ConvertKeyValueArraysToMessage(
- JNIEnv *env, jobjectArray keys, jobjectArray values,
- sp<AMessage> *msg);
-
// -----------Utility functions used by ImageReader/Writer JNI-----------------
typedef CpuConsumer::LockedBuffer LockedImage;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 06a7182e4b1d..1f89d86947a1 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -18,7 +18,7 @@
#include "utils/Log.h"
#include "utils/String8.h"
-#include "android_media_Utils.h"
+#include "android_media_Streams.h"
#include "mtp.h"
#include "IMtpDatabase.h"
#include "MtpDataPacket.h"
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
index 2db575bf5a13..3fecd53b43e2 100644
--- a/native/android/choreographer.cpp
+++ b/native/android/choreographer.cpp
@@ -70,6 +70,8 @@ private:
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) override;
void scheduleCallbacks();
@@ -164,6 +166,13 @@ void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool c
this, displayId, toString(connected));
}
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
+ int32_t configId) {
+ ALOGV("choreographer %p ~ received config changed event (displayId=%"
+ ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
+ this, displayId, toString(configId));
+}
+
void Choreographer::handleMessage(const Message& message) {
switch (message.what) {
case MSG_SCHEDULE_CALLBACKS:
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index 6cf72a45a06b..ba361c40f5c6 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -26,6 +26,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
/**
* Observes the settings for {@link Assistant}.
@@ -103,7 +104,7 @@ final class AssistantSettings extends ContentObserver {
private void registerDeviceConfigs() {
DeviceConfig.addOnPropertyChangedListener(
- DeviceConfig.NotificationAssistant.NAMESPACE,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
this::postToHandler,
this::onDeviceConfigPropertyChanged);
@@ -117,7 +118,7 @@ final class AssistantSettings extends ContentObserver {
@VisibleForTesting
void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
- if (!DeviceConfig.NotificationAssistant.NAMESPACE.equals(namespace)) {
+ if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: "
+ namespace + " " + name + "=" + value);
return;
@@ -128,17 +129,17 @@ final class AssistantSettings extends ContentObserver {
private void updateFromDeviceConfigFlags() {
mGenerateReplies = DeviceConfigHelper.getBoolean(
- DeviceConfig.NotificationAssistant.GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
mGenerateActions = DeviceConfigHelper.getBoolean(
- DeviceConfig.NotificationAssistant.GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
mMaxMessagesToExtract = DeviceConfigHelper.getInteger(
- DeviceConfig.NotificationAssistant.MAX_MESSAGES_TO_EXTRACT,
+ SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
DEFAULT_MAX_MESSAGES_TO_EXTRACT);
mMaxSuggestions = DeviceConfigHelper.getInteger(
- DeviceConfig.NotificationAssistant.MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS);
+ SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS);
mOnUpdateRunnable.run();
}
@@ -193,8 +194,7 @@ final class AssistantSettings extends ContentObserver {
private static String getValue(String key) {
return DeviceConfig.getProperty(
- DeviceConfig.NotificationAssistant.NAMESPACE,
- key);
+ DeviceConfig.NAMESPACE_SYSTEMUI, key);
}
}
@@ -202,4 +202,4 @@ final class AssistantSettings extends ContentObserver {
AssistantSettings createAndRegister(Handler handler, ContentResolver resolver, int userId,
Runnable onUpdateRunnable);
}
-} \ No newline at end of file
+}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index d890c1ae81fb..851e2f269a95 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -17,7 +17,6 @@
package android.ext.services.notification;
import static android.ext.services.notification.AssistantSettings.DEFAULT_MAX_SUGGESTIONS;
-import static android.provider.DeviceConfig.NotificationAssistant;
import static android.provider.DeviceConfig.setProperty;
import static junit.framework.Assert.assertFalse;
@@ -30,12 +29,15 @@ import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
import android.os.Handler;
import android.os.Looper;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.testing.TestableContext;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -49,7 +51,7 @@ import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class AssistantSettingsTest {
private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
- "device_config delete " + NotificationAssistant.NAMESPACE;
+ "device_config delete " + DeviceConfig.NAMESPACE_SYSTEMUI;
private static final int USER_ID = 5;
@@ -87,13 +89,13 @@ public class AssistantSettingsTest {
@Test
public void testGenerateRepliesDisabled() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false");
assertFalse(mAssistantSettings.mGenerateReplies);
@@ -102,13 +104,13 @@ public class AssistantSettingsTest {
@Test
public void testGenerateRepliesEnabled() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"true",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"true");
assertTrue(mAssistantSettings.mGenerateReplies);
@@ -117,25 +119,25 @@ public class AssistantSettingsTest {
@Test
public void testGenerateRepliesEmptyFlag() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"false");
assertFalse(mAssistantSettings.mGenerateReplies);
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_REPLIES,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
"");
// Go back to the default value.
@@ -145,13 +147,13 @@ public class AssistantSettingsTest {
@Test
public void testGenerateActionsDisabled() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false");
assertFalse(mAssistantSettings.mGenerateActions);
@@ -160,13 +162,13 @@ public class AssistantSettingsTest {
@Test
public void testGenerateActionsEnabled() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"true",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"true");
assertTrue(mAssistantSettings.mGenerateActions);
@@ -175,25 +177,25 @@ public class AssistantSettingsTest {
@Test
public void testGenerateActionsEmptyFlag() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"false");
assertFalse(mAssistantSettings.mGenerateActions);
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.GENERATE_ACTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
"");
// Go back to the default value.
@@ -203,13 +205,13 @@ public class AssistantSettingsTest {
@Test
public void testMaxMessagesToExtract() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.MAX_MESSAGES_TO_EXTRACT,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
"10",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.MAX_MESSAGES_TO_EXTRACT,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
"10");
assertEquals(10, mAssistantSettings.mMaxMessagesToExtract);
@@ -218,13 +220,13 @@ public class AssistantSettingsTest {
@Test
public void testMaxSuggestions() {
setProperty(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.MAX_SUGGESTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
"5",
false /* makeDefault */);
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.MAX_SUGGESTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
"5");
assertEquals(5, mAssistantSettings.mMaxSuggestions);
@@ -233,8 +235,8 @@ public class AssistantSettingsTest {
@Test
public void testMaxSuggestionsEmpty() {
mAssistantSettings.onDeviceConfigPropertyChanged(
- NotificationAssistant.NAMESPACE,
- NotificationAssistant.MAX_SUGGESTIONS,
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS,
"");
assertEquals(DEFAULT_MAX_SUGGESTIONS, mAssistantSettings.mMaxSuggestions);
@@ -278,13 +280,14 @@ public class AssistantSettingsTest {
private static void clearDeviceConfig() throws IOException {
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + NotificationAssistant.GENERATE_ACTIONS);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS);
uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + NotificationAssistant.GENERATE_REPLIES);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES);
uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + NotificationAssistant.MAX_MESSAGES_TO_EXTRACT);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " "
+ + SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT);
uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + NotificationAssistant.MAX_SUGGESTIONS);
+ CLEAR_DEVICE_CONFIG_KEY_CMD + " " + SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS);
}
}
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java b/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
index 6ea1e3d49dd4..225dc0f4bfdc 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
@@ -30,7 +30,9 @@ import com.android.server.connectivity.nano.WifiData;
import com.google.protobuf.nano.MessageNano;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* Class to record the stats of detection level information for data stall.
@@ -96,6 +98,22 @@ public final class DataStallDetectionStats {
return sb.toString();
}
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof DataStallDetectionStats)) return false;
+ final DataStallDetectionStats other = (DataStallDetectionStats) o;
+ return (mNetworkType == other.mNetworkType)
+ && (mEvaluationType == other.mEvaluationType)
+ && Arrays.equals(mWifiInfo, other.mWifiInfo)
+ && Arrays.equals(mCellularInfo, other.mCellularInfo)
+ && Arrays.equals(mDns, other.mDns);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetworkType, mEvaluationType, mWifiInfo, mCellularInfo, mDns);
+ }
+
/**
* Utility to create an instance of {@Link DataStallDetectionStats}
*
@@ -163,16 +181,17 @@ public final class DataStallDetectionStats {
}
private static int getWifiBand(@Nullable final WifiInfo info) {
- if (info != null) {
- int freq = info.getFrequency();
- // Refer to ScanResult.is5GHz() and ScanResult.is24GHz().
- if (freq > 4900 && freq < 5900) {
- return DataStallEventProto.AP_BAND_5GHZ;
- } else if (freq > 2400 && freq < 2500) {
- return DataStallEventProto.AP_BAND_2GHZ;
- }
+ if (info == null) return DataStallEventProto.AP_BAND_UNKNOWN;
+
+ int freq = info.getFrequency();
+ // Refer to ScanResult.is5GHz() and ScanResult.is24GHz().
+ if (freq > 4900 && freq < 5900) {
+ return DataStallEventProto.AP_BAND_5GHZ;
+ } else if (freq > 2400 && freq < 2500) {
+ return DataStallEventProto.AP_BAND_2GHZ;
+ } else {
+ return DataStallEventProto.AP_BAND_UNKNOWN;
}
- return DataStallEventProto.AP_BAND_UNKNOWN;
}
/**
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 3c129ce81b65..e82a5d7b4881 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -729,7 +729,8 @@ public class NetworkMonitor extends StateMachine {
return stats.build();
}
- private void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
+ @VisibleForTesting
+ protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
final int size = mDnsStallDetector.mResultIndices.size();
for (int i = 1; i <= DEFAULT_DNS_LOG_SIZE && i <= size; i++) {
final int index = mDnsStallDetector.mResultIndices.indexOf(size - i);
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index beb975d745c2..ddb7030d314a 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -30,7 +30,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -40,6 +39,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetworkMonitorCallbacks;
@@ -49,9 +49,11 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.metrics.DataStallDetectionStats;
import android.net.metrics.DataStallStatsUtils;
import android.net.metrics.IpConnectivityLog;
import android.net.util.SharedLog;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.ConditionVariable;
@@ -60,6 +62,7 @@ import android.os.SystemClock;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.telephony.CellSignalStrength;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -101,6 +104,7 @@ public class NetworkMonitorTest {
private @Mock INetworkMonitorCallbacks mCallbacks;
private @Spy Network mNetwork = new Network(TEST_NETID);
private @Mock DataStallStatsUtils mDataStallStatsUtils;
+ private @Mock WifiInfo mWifiInfo;
private static final int TEST_NETID = 4242;
@@ -108,10 +112,12 @@ public class NetworkMonitorTest {
private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
+ private static final String TEST_MCCMNC = "123456";
private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
private static final int RETURN_CODE_DNS_SUCCESS = 0;
private static final int RETURN_CODE_DNS_TIMEOUT = 255;
+ private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
private static final int HANDLER_TIMEOUT_MS = 1000;
@@ -202,6 +208,11 @@ public class NetworkMonitorTest {
protected void setLastProbeTime(long time) {
mProbeTime = time;
}
+
+ @Override
+ protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
+ generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+ }
}
private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
@@ -387,7 +398,7 @@ public class NetworkMonitorTest {
public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
+ makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertTrue(wrappedMonitor.isDataStall());
}
@@ -398,7 +409,7 @@ public class NetworkMonitorTest {
assertFalse(wrappedMonitor.isDataStall());
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
+ makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertTrue(wrappedMonitor.isDataStall());
}
@@ -432,7 +443,7 @@ public class NetworkMonitorTest {
// Test dns events happened in valid dns time threshold.
WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
+ makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertFalse(wrappedMonitor.isDataStall());
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
assertTrue(wrappedMonitor.isDataStall());
@@ -441,7 +452,7 @@ public class NetworkMonitorTest {
setValidDataStallDnsTimeThreshold(0);
wrappedMonitor = makeMeteredWrappedNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
+ makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertFalse(wrappedMonitor.isDataStall());
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
assertFalse(wrappedMonitor.isDataStall());
@@ -514,7 +525,7 @@ public class NetworkMonitorTest {
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 5);
assertTrue(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, times(1)).write(eq(anyObject()), eq(anyObject()));
+ verify(mDataStallStatsUtils, times(1)).write(any(), any());
}
@Test
@@ -523,8 +534,44 @@ public class NetworkMonitorTest {
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 3);
assertFalse(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, times(0)).write(eq(anyObject()), eq(anyObject()));
+ verify(mDataStallStatsUtils, never()).write(any(), any());
}
+
+ @Test
+ public void testCollectDataStallMetrics() {
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+
+ when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+ when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
+ when(mTelephony.getSimOperator()).thenReturn(TEST_MCCMNC);
+
+ DataStallDetectionStats.Builder stats =
+ new DataStallDetectionStats.Builder()
+ .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
+ .setNetworkType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setCellData(TelephonyManager.NETWORK_TYPE_LTE /* radioType */,
+ true /* roaming */,
+ TEST_MCCMNC /* networkMccmnc */,
+ TEST_MCCMNC /* simMccmnc */,
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN /* signalStrength */);
+ generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+
+ assertEquals(wrappedMonitor.buildDataStallDetectionStats(
+ NetworkCapabilities.TRANSPORT_CELLULAR), stats.build());
+
+ when(mWifi.getConnectionInfo()).thenReturn(mWifiInfo);
+
+ stats = new DataStallDetectionStats.Builder()
+ .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
+ .setNetworkType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setWiFiData(mWifiInfo);
+ generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
+
+ assertEquals(
+ wrappedMonitor.buildDataStallDetectionStats(NetworkCapabilities.TRANSPORT_WIFI),
+ stats.build());
+ }
+
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
for (int i = 0; i < count; i++) {
wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
@@ -614,5 +661,11 @@ public class NetworkMonitorTest {
private void setStatus(HttpURLConnection connection, int status) throws IOException {
doReturn(status).when(connection).getResponseCode();
}
+
+ private void generateTimeoutDnsEvent(DataStallDetectionStats.Builder stats, int num) {
+ for (int i = 0; i < num; i++) {
+ stats.addDnsEvent(RETURN_CODE_DNS_TIMEOUT, 123456789 /* timeMs */);
+ }
+ }
}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index caa928f43cc9..730e9e134e3d 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -29,7 +29,7 @@ android_library {
resource_dirs: ["res"],
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
min_sdk_version: "21",
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
index b053317b9de1..4bc68b333cc6 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
@@ -25,8 +25,7 @@
<View
android:id="@+id/bar_view"
android:layout_width="8dp"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorAccent"/>
+ android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/icon_view"
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 647d0800fe82..4876cb6e1f28 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -18,7 +18,7 @@
<resources>
<style name="BarViewStyle">
<item name="android:layout_width">0dp</item>
- <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_height">226dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_marginStart">8dp</item>
<item name="android:layout_marginEnd">8dp</item>
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index 3b87fcabb3fc..1003c974deb3 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -160,8 +160,11 @@ public class BarChartPreference extends Preference {
// If the state is loading, we just show a blank view.
if (mIsLoading) {
+ holder.itemView.setVisibility(View.INVISIBLE);
return;
}
+ holder.itemView.setVisibility(View.VISIBLE);
+
// We must show title of bar chart.
bindChartTitleView(holder);
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
index 6bf61ae70312..3ef0235940b1 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -89,7 +89,7 @@ public class BarView extends LinearLayout {
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.settings_bar_view, this);
setOrientation(LinearLayout.VERTICAL);
- setGravity(Gravity.CENTER);
+ setGravity(Gravity.CENTER | Gravity.BOTTOM);
mBarView = findViewById(R.id.bar_view);
mIcon = findViewById(R.id.icon_view);
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
new file mode 100644
index 000000000000..337106bb5f1b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
@@ -0,0 +1,404 @@
+/*
+ * 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.settingslib.graph
+
+import android.content.Context
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.util.PathParser
+import android.util.TypedValue
+
+import com.android.settingslib.R
+import com.android.settingslib.Utils
+
+/**
+ * A battery meter drawable that respects paths configured in
+ * frameworks/base/core/res/res/values/config.xml to allow for an easily overrideable battery icon
+ */
+open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) : Drawable() {
+
+ // Need to load:
+ // 1. perimeter shape
+ // 2. fill mask (if smaller than perimeter, this would create a fill that
+ // doesn't touch the walls
+ private val perimeterPath = Path()
+ private val scaledPerimeter = Path()
+ // Fill will cover the whole bounding rect of the fillMask, and be masked by the path
+ private val fillMask = Path()
+ private val scaledFill = Path()
+ // Based off of the mask, the fill will interpolate across this space
+ private val fillRect = RectF()
+ // Top of this rect changes based on level, 100% == fillRect
+ private val levelRect = RectF()
+ private val levelPath = Path()
+ // Updates the transform of the paths when our bounds change
+ private val scaleMatrix = Matrix()
+ private val padding = Rect()
+ // The net result of fill + perimeter paths
+ private val unifiedPath = Path()
+
+ // Bolt path (used while charging)
+ private val boltPath = Path()
+ private val scaledBolt = Path()
+
+ // Plus sign (used for power save mode)
+ private val plusPath = Path()
+ private val scaledPlus = Path()
+
+ private var intrinsicHeight: Int
+ private var intrinsicWidth: Int
+
+ // To implement hysteresis, keep track of the need to invert the interior icon of the battery
+ private var invertFillIcon = false
+
+ // Colors can be configured based on battery level (see res/values/arrays.xml)
+ private var colorLevels: IntArray
+
+ private var fillColor: Int = Color.MAGENTA
+ private var backgroundColor: Int = Color.MAGENTA
+ // updated whenever level changes
+ private var levelColor: Int = Color.MAGENTA
+
+ // Dual tone implies that battery level is a clipped overlay over top of the whole shape
+ private var dualTone = false
+
+ private val invalidateRunnable: () -> Unit = {
+ invalidateSelf()
+ }
+
+ open var criticalLevel: Int = 0
+
+ var charging = false
+ set(value) {
+ field = value
+ postInvalidate()
+ }
+
+ var powerSaveEnabled = false
+ set(value) {
+ field = value
+ postInvalidate()
+ }
+
+ private val fillColorStrokePaint: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.isDither = true
+ p.strokeWidth = 5f
+ p.style = Paint.Style.STROKE
+ p.blendMode = BlendMode.SRC
+ p.strokeMiter = 5f
+ p
+ }
+
+ private val fillColorStrokeProtection: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.isDither = true
+ p.strokeWidth = 5f
+ p.style = Paint.Style.STROKE
+ p.blendMode = BlendMode.CLEAR
+ p.strokeMiter = 5f
+ p
+ }
+
+ private val fillPaint: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.alpha = 255
+ p.isDither = true
+ p.strokeWidth = 0f
+ p.style = Paint.Style.FILL_AND_STROKE
+ p
+ }
+
+ // Only used if dualTone is set to true
+ private val dualToneBackgroundFill: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.alpha = 255
+ p.isDither = true
+ p.strokeWidth = 0f
+ p.style = Paint.Style.FILL_AND_STROKE
+ p
+ }
+
+ init {
+ val density = context.resources.displayMetrics.density
+ intrinsicHeight = (Companion.HEIGHT * density).toInt()
+ intrinsicWidth = (Companion.WIDTH * density).toInt()
+
+ val res = context.resources
+ val levels = res.obtainTypedArray(R.array.batterymeter_color_levels)
+ val colors = res.obtainTypedArray(R.array.batterymeter_color_values)
+ val N = levels.length()
+ colorLevels = IntArray(2 * N)
+ for (i in 0 until N) {
+ colorLevels[2 * i] = levels.getInt(i, 0)
+ if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
+ colorLevels[2 * i + 1] = Utils.getColorAttrDefaultColor(context,
+ colors.getThemeAttributeId(i, 0))
+ } else {
+ colorLevels[2 * i + 1] = colors.getColor(i, 0)
+ }
+ }
+ levels.recycle()
+ colors.recycle()
+
+ criticalLevel = context.resources.getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel)
+
+ loadPaths()
+ }
+
+ override fun draw(c: Canvas) {
+ unifiedPath.reset()
+ levelPath.reset()
+ levelRect.set(fillRect)
+ val fillFraction = level / 100f
+ val fillTop =
+ if (level >= 95)
+ fillRect.top
+ else
+ fillRect.top + (fillRect.height() * (1 - fillFraction))
+
+ levelRect.top = Math.floor(fillTop.toDouble()).toFloat()
+ levelPath.addRect(levelRect, Path.Direction.CCW)
+
+ // The perimeter should never change
+ unifiedPath.addPath(scaledPerimeter)
+ // IF drawing dual tone, the level is used only to clip the whole drawable path
+ if (!dualTone) {
+ unifiedPath.op(levelPath, Path.Op.UNION)
+ }
+
+ fillPaint.color = levelColor
+
+ // Deal with unifiedPath clipping before it draws
+ if (charging) {
+ // Clip out the bolt shape
+ unifiedPath.op(scaledBolt, Path.Op.DIFFERENCE)
+ if (!invertFillIcon) {
+ c.drawPath(scaledBolt, fillPaint)
+ }
+ } else if (powerSaveEnabled) {
+ // Clip out the plus shape
+ unifiedPath.op(scaledPlus, Path.Op.DIFFERENCE)
+ if (!invertFillIcon) {
+ c.drawPath(scaledPlus, fillPaint)
+ }
+ }
+
+ if (dualTone) {
+ // Dual tone means we draw the shape again, clipped to the charge level
+ c.drawPath(unifiedPath, dualToneBackgroundFill)
+ c.save()
+ c.clipRect(0f,
+ bounds.bottom - bounds.height() * fillFraction,
+ bounds.right.toFloat(),
+ bounds.bottom.toFloat())
+ c.drawPath(unifiedPath, fillPaint)
+ c.restore()
+ } else {
+ // Non dual-tone means we draw the perimeter (with the level fill), and potentially
+ // draw the fill again with a critical color
+ fillPaint.color = fillColor
+ c.drawPath(unifiedPath, fillPaint)
+ fillPaint.color = levelColor
+
+ // Show colorError below this level
+ if (level <= Companion.CRITICAL_LEVEL && !charging) {
+ c.save()
+ c.clipPath(scaledFill)
+ c.drawPath(levelPath, fillPaint)
+ c.restore()
+ }
+ }
+
+ if (charging) {
+ c.clipOutPath(scaledBolt)
+ if (invertFillIcon) {
+ c.drawPath(scaledBolt, fillColorStrokePaint)
+ } else {
+ c.drawPath(scaledBolt, fillColorStrokeProtection)
+ }
+ } else if (powerSaveEnabled) {
+ c.clipOutPath(scaledPlus)
+ if (invertFillIcon) {
+ c.drawPath(scaledPlus, fillColorStrokePaint)
+ } else {
+ c.drawPath(scaledPlus, fillColorStrokeProtection)
+ }
+ }
+ }
+
+ private fun batteryColorForLevel(level: Int): Int {
+ return when {
+ charging || powerSaveEnabled -> fillPaint.color
+ else -> getColorForLevel(level)
+ }
+ }
+
+ private fun getColorForLevel(level: Int): Int {
+ var thresh: Int
+ var color = 0
+ var i = 0
+ while (i < colorLevels.size) {
+ thresh = colorLevels[i]
+ color = colorLevels[i + 1]
+ if (level <= thresh) {
+
+ // Respect tinting for "normal" level
+ return if (i == colorLevels.size - 2) {
+ fillColor
+ } else {
+ color
+ }
+ }
+ i += 2
+ }
+ return color
+ }
+
+ /**
+ * Alpha is unused internally, and should be defined in the colors passed to {@link setColors}.
+ * Further, setting an alpha for a dual tone battery meter doesn't make sense without bounds
+ * defining the minimum background fill alpha. This is because fill + background must be equal
+ * to the net alpha passed in here.
+ */
+ override fun setAlpha(alpha: Int) {
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ fillPaint.colorFilter = colorFilter
+ fillColorStrokePaint.colorFilter = colorFilter
+ dualToneBackgroundFill.colorFilter = colorFilter
+ }
+
+ /**
+ * Deprecated, but required by Drawable
+ */
+ override fun getOpacity(): Int {
+ return PixelFormat.OPAQUE
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ return intrinsicHeight
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return intrinsicWidth
+ }
+
+ /**
+ * Set the fill level
+ */
+ public open fun setBatteryLevel(l: Int) {
+ invertFillIcon = if (l >= 67) true else if (l <= 33) false else invertFillIcon
+ level = l
+ levelColor = batteryColorForLevel(level)
+ invalidateSelf()
+ }
+
+ public fun getBatteryLevel(): Int {
+ return level
+ }
+
+ override fun onBoundsChange(bounds: Rect?) {
+ super.onBoundsChange(bounds)
+ updateSize()
+ }
+
+ fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
+ padding.left = left
+ padding.top = top
+ padding.right = right
+ padding.bottom = bottom
+
+ updateSize()
+ }
+
+ fun setColors(fgColor: Int, bgColor: Int, singleToneColor: Int) {
+ fillColor = if (dualTone) fgColor else singleToneColor
+
+ fillPaint.color = fillColor
+ fillColorStrokePaint.color = fillColor
+
+ backgroundColor = bgColor
+ dualToneBackgroundFill.color = bgColor
+
+ invalidateSelf()
+ }
+
+ private fun postInvalidate() {
+ unscheduleSelf(invalidateRunnable)
+ scheduleSelf(invalidateRunnable, 0)
+ }
+
+ private fun updateSize() {
+ val b = bounds
+ if (b.isEmpty) {
+ scaleMatrix.setScale(1f, 1f)
+ } else {
+ scaleMatrix.setScale((b.right / Companion.WIDTH), (b.bottom / Companion.HEIGHT))
+ }
+
+ perimeterPath.transform(scaleMatrix, scaledPerimeter)
+ fillMask.transform(scaleMatrix, scaledFill)
+ scaledFill.computeBounds(fillRect, true)
+ boltPath.transform(scaleMatrix, scaledBolt)
+ plusPath.transform(scaleMatrix, scaledPlus)
+ }
+
+ private fun loadPaths() {
+ val pathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterPerimeterPath)
+ perimeterPath.set(PathParser.createPathFromPathData(pathString))
+ val b = RectF()
+ perimeterPath.computeBounds(b, true)
+
+ val fillMaskString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterFillMask)
+ fillMask.set(PathParser.createPathFromPathData(fillMaskString))
+ // Set the fill rect so we can calculate the fill properly
+ fillMask.computeBounds(fillRect, true)
+
+ val boltPathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterBoltPath)
+ boltPath.set(PathParser.createPathFromPathData(boltPathString))
+
+ val plusPathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterPowersavePath)
+ plusPath.set(PathParser.createPathFromPathData(plusPathString))
+
+ dualTone = context.resources.getBoolean(
+ com.android.internal.R.bool.config_batterymeterDualTone)
+ }
+
+ companion object {
+ private const val TAG = "ThemedBatteryDrawable"
+ private const val WIDTH = 12f
+ private const val HEIGHT = 20f
+ private const val CRITICAL_LEVEL = 15
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index 2a1281027169..a31b71e2cd0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -59,6 +59,5 @@ public class FooterPreference extends Preference {
setIcon(R.drawable.ic_info_outline_24);
setKey(KEY_FOOTER);
setOrder(ORDER_FOOTER);
- setSelectable(false);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 1080cf49e551..3acca2a7ef75 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -305,7 +305,7 @@ public class BarChartPreferenceTest {
}
@Test
- public void onBindViewHolder_loadingStateIsTrue_shouldNotInitAnyView() {
+ public void onBindViewHolder_loadingStateIsTrue_shouldHideAllViews() {
final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app);
viewInfo.setClickListener(v -> {
});
@@ -317,8 +317,7 @@ public class BarChartPreferenceTest {
mPreference.onBindViewHolder(mHolder);
- assertThat(TextUtils.isEmpty(mTitleView.getText())).isTrue();
- assertThat(TextUtils.isEmpty(mDetailsView.getText())).isTrue();
+ assertThat(mHolder.itemView.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
@@ -334,6 +333,7 @@ public class BarChartPreferenceTest {
mPreference.onBindViewHolder(mHolder);
+ assertThat(mHolder.itemView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(TextUtils.isEmpty(mTitleView.getText())).isFalse();
assertThat(TextUtils.isEmpty(mDetailsView.getText())).isFalse();
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0da3b10778e9..fc6ef2bcede2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -146,6 +146,7 @@
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
<uses-permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS" />
<uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />
+ <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
diff --git a/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml b/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
deleted file mode 100644
index a76b7b1c8f7b..000000000000
--- a/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating"/>
- <corners
- android:topLeftRadius="@dimen/corner_size"
- android:topRightRadius="@dimen/corner_size"/>
- </shape>
- </item>
-</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index a8b1b2e3531f..56a3cd5499e3 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -29,10 +29,9 @@
<FrameLayout
android:id="@+id/header_permission_wrapper"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:animateLayoutChanges="true"
- android:background="@drawable/bubble_expanded_header_bg">
+ android:animateLayoutChanges="true">
<LinearLayout
android:id="@+id/header_layout"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
index bc15f2c46b47..665fc3fbf3da 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
@@ -54,9 +54,6 @@
android:orientation="vertical"
android:gravity="start"
/>
-
- <include android:id="@+id/overflow" layout="@layout/ongoing_privacy_dialog_item"
- android:visibility="gone" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 536bc4edf341..50cf37beb878 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -44,8 +44,9 @@
<!-- Height of the battery icon in the status bar. -->
<dimen name="status_bar_battery_icon_height">13.0dp</dimen>
- <!-- Width of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_width">8.5dp</dimen>
+ <!-- Width of the battery icon in the status bar. The battery drawable assumes a 12x20 canvas,
+ so the width of the icon should be 13.0dp * (12.0 / 20.0) -->
+ <dimen name="status_bar_battery_icon_width">7.8dp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
@@ -1049,4 +1050,7 @@
<dimen name="bubble_pointer_margin">8dp</dimen>
<!-- Height of the permission prompt shown with bubbles -->
<dimen name="bubble_permission_height">120dp</dimen>
+
+ <!-- Size of the RAT type for CellularTile -->
+ <dimen name="celltile_rat_type_size">10sp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1e411cf7f92b..30dbc8bd1d20 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -216,6 +216,12 @@
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
+ <!-- This is hard coded to be sans-serif-condensed to match the icons -->
+ <style name="TextAppearance.RATBadge" parent="@style/TextAppearance.QS.TileLabel.Secondary">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textSize">@dimen/celltile_rat_type_size</item>
+ </style>
+
<style name="TextAppearance.QS.CarrierInfo">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textSize">@dimen/qs_carrier_info_text_size</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index 0cde9daa81b3..e554dcd36100 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -27,26 +27,26 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
+import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.InputEvent;
-import android.view.IWindowManager;
-import android.view.MotionEvent;
import android.view.WindowManagerGlobal;
import java.io.PrintWriter;
/**
- * Manages the input consumer that allows the SystemUI to directly receive touch input.
+ * Manages the input consumer that allows the SystemUI to directly receive input.
*/
public class InputConsumerController {
private static final String TAG = InputConsumerController.class.getSimpleName();
/**
- * Listener interface for callers to subscribe to touch events.
+ * Listener interface for callers to subscribe to input events.
*/
- public interface TouchListener {
- boolean onTouchEvent(MotionEvent ev);
+ public interface InputListener {
+ /** Handles any input event. */
+ boolean onInputEvent(InputEvent ev);
}
/**
@@ -71,9 +71,8 @@ public class InputConsumerController {
public void onInputEvent(InputEvent event) {
boolean handled = true;
try {
- if (mListener != null && event instanceof MotionEvent) {
- MotionEvent ev = (MotionEvent) event;
- handled = mListener.onTouchEvent(ev);
+ if (mListener != null) {
+ handled = mListener.onInputEvent(event);
}
} finally {
finishInputEvent(event, handled);
@@ -86,7 +85,7 @@ public class InputConsumerController {
private final String mName;
private InputEventReceiver mInputEventReceiver;
- private TouchListener mListener;
+ private InputListener mListener;
private RegistrationListener mRegistrationListener;
/**
@@ -115,9 +114,9 @@ public class InputConsumerController {
}
/**
- * Sets the touch listener.
+ * Sets the input listener.
*/
- public void setTouchListener(TouchListener listener) {
+ public void setInputListener(InputListener listener) {
mListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a055950a5522..4cb8d90927fd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -34,6 +34,8 @@ import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
+import java.util.Arrays;
+
/**
* Base class for PIN and password unlock screens.
*/
@@ -124,18 +126,19 @@ 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 String entry = getPasswordText();
+ final byte[] entry = getPasswordText();
setPasswordEntryInputEnabled(false);
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
}
final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
// to avoid accidental lockout, only count attempts that are long enough to be a
// real password. This may require some tweaking.
setPasswordEntryInputEnabled(true);
onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
+ Arrays.fill(entry, (byte) 0);
return;
}
@@ -157,6 +160,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
true /* isValidPassword */);
+ Arrays.fill(entry, (byte) 0);
}
@Override
@@ -171,6 +175,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
onPasswordChecked(userId, false /* matched */, timeoutMs,
true /* isValidPassword */);
}
+ Arrays.fill(entry, (byte) 0);
}
@Override
@@ -181,6 +186,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
LatencyTracker.getInstance(mContext).onActionEnd(
ACTION_CHECK_CREDENTIAL_UNLOCKED);
}
+ Arrays.fill(entry, (byte) 0);
}
});
}
@@ -211,7 +217,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
protected abstract void resetPasswordText(boolean animate, boolean announce);
- protected abstract String getPasswordText();
+ protected abstract byte[] getPasswordText();
protected abstract void setPasswordEntryEnabled(boolean enabled);
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 583dac7996ae..9dd97170437d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -17,7 +17,6 @@ package com.android.keyguard;
import static android.view.Display.DEFAULT_DISPLAY;
-import android.annotation.Nullable;
import android.app.Presentation;
import android.content.Context;
import android.graphics.Point;
@@ -32,15 +31,11 @@ import android.view.DisplayInfo;
import android.view.View;
import android.view.WindowManager;
-import java.util.function.BooleanSupplier;
-
// TODO(multi-display): Support multiple external displays
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
- private final ViewMediatorCallback mCallback;
-
private final MediaRouter mMediaRouter;
private final DisplayManager mDisplayService;
private final Context mContext;
@@ -57,7 +52,7 @@ public class KeyguardDisplayManager {
public void onDisplayAdded(int displayId) {
final Display display = mDisplayService.getDisplay(displayId);
if (mShowing) {
- notifyIfChanged(() -> showPresentation(display));
+ showPresentation(display);
}
}
@@ -76,13 +71,12 @@ public class KeyguardDisplayManager {
@Override
public void onDisplayRemoved(int displayId) {
- notifyIfChanged(() -> hidePresentation(displayId));
+ hidePresentation(displayId);
}
};
- public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
+ public KeyguardDisplayManager(Context context) {
mContext = context;
- mCallback = callback;
mMediaRouter = mContext.getSystemService(MediaRouter.class);
mDisplayService = mContext.getSystemService(DisplayManager.class);
mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -138,42 +132,13 @@ public class KeyguardDisplayManager {
/**
* @param displayId The id of the display to hide the presentation off.
- * @return {@code true} if the a presentation was removed.
- * {@code false} if the presentation was not added before.
*/
- private boolean hidePresentation(int displayId) {
+ private void hidePresentation(int displayId) {
final Presentation presentation = mPresentations.get(displayId);
if (presentation != null) {
presentation.dismiss();
mPresentations.remove(displayId);
- return true;
- }
- return false;
- }
-
- private void notifyIfChanged(BooleanSupplier updateMethod) {
- if (updateMethod.getAsBoolean()) {
- final int[] displayList = getPresentationDisplayIds();
- mCallback.onSecondaryDisplayShowingChanged(displayList);
- }
- }
-
- /**
- * @return An array of displayId's on which a {@link KeyguardPresentation} is showing on.
- */
- @Nullable
- private int[] getPresentationDisplayIds() {
- final int size = mPresentations.size();
- if (size == 0) return null;
-
- final int[] displayIds = new int[size];
- for (int i = mPresentations.size() - 1; i >= 0; i--) {
- final Presentation presentation = mPresentations.valueAt(i);
- if (presentation != null) {
- displayIds[i] = presentation.getDisplay().getDisplayId();
- }
}
- return displayIds;
}
public void show() {
@@ -181,7 +146,7 @@ public class KeyguardDisplayManager {
if (DEBUG) Log.v(TAG, "show");
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
- notifyIfChanged(() -> updateDisplays(true /* showing */));
+ updateDisplays(true /* showing */);
}
mShowing = true;
}
@@ -190,7 +155,7 @@ public class KeyguardDisplayManager {
if (mShowing) {
if (DEBUG) Log.v(TAG, "hide");
mMediaRouter.removeCallback(mMediaRouterCallback);
- notifyIfChanged(() -> updateDisplays(false /* showing */));
+ updateDisplays(false /* showing */);
}
mShowing = false;
}
@@ -200,19 +165,19 @@ public class KeyguardDisplayManager {
@Override
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
- notifyIfChanged(() -> updateDisplays(mShowing));
+ updateDisplays(mShowing);
}
@Override
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
- notifyIfChanged(() -> updateDisplays(mShowing));
+ updateDisplays(mShowing);
}
@Override
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
- notifyIfChanged(() -> updateDisplays(mShowing));
+ updateDisplays(mShowing);
}
};
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 261f391839b3..185edbfa9856 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -241,8 +241,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
@Override
- protected String getPasswordText() {
- return mPasswordEntry.getText().toString();
+ protected byte[] getPasswordText() {
+ return charSequenceToByteArray(mPasswordEntry.getText());
}
@Override
@@ -377,4 +377,18 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock);
}
+
+ /*
+ * This method avoids creating a new string when getting a byte array from EditView#getText().
+ */
+ private static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 3cc18ddf3b2a..ecafc3408224 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -165,8 +165,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
@Override
- protected String getPasswordText() {
- return mPasswordEntry.getText();
+ protected byte[] getPasswordText() {
+ return charSequenceToByteArray(mPasswordEntry.getText());
}
@Override
@@ -264,4 +264,18 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
}
+
+ /*
+ * This method avoids creating a new string when getting a byte array from EditView#getText().
+ */
+ private static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index a07c5cbde956..6e0613036678 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -96,11 +96,6 @@ public interface ViewMediatorCallback {
int getBouncerPromptReason();
/**
- * Invoked when the secondary displays showing a keyguard window changes.
- */
- void onSecondaryDisplayShowingChanged(int[] displayId);
-
- /**
* Consumes a message that was enqueued to be displayed on the next time the bouncer shows up.
* @return Message that should be displayed above the challenge.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 200679432200..592b6039d69d 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -46,7 +46,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.settingslib.Utils;
-import com.android.settingslib.graph.BatteryMeterDrawableBase;
+import com.android.settingslib.graph.ThemedBatteryDrawable;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
@@ -76,7 +76,7 @@ public class BatteryMeterView extends LinearLayout implements
public static final int MODE_OFF = 2;
public static final int MODE_ESTIMATE = 3;
- private final BatteryMeterDrawableBase mDrawable;
+ private final ThemedBatteryDrawable mDrawable;
private final String mSlotBattery;
private final ImageView mBatteryIconView;
private final CurrentUserTracker mUserTracker;
@@ -94,9 +94,11 @@ public class BatteryMeterView extends LinearLayout implements
private boolean mIsSubscribedForTunerUpdates;
private boolean mCharging;
+ private int mDarkModeSingleToneColor;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
+ private int mLightModeSingleToneColor;
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
private int mUser;
@@ -106,6 +108,7 @@ public class BatteryMeterView extends LinearLayout implements
*/
private boolean mUseWallpaperTextColors;
+ private int mNonAdaptedSingleToneColor;
private int mNonAdaptedForegroundColor;
private int mNonAdaptedBackgroundColor;
@@ -127,7 +130,7 @@ public class BatteryMeterView extends LinearLayout implements
defStyle, 0);
final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
context.getColor(R.color.meter_background_color));
- mDrawable = new BatteryMeterDrawableBase(context, frameColor);
+ mDrawable = new ThemedBatteryDrawable(context, frameColor);
atts.recycle();
mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
@@ -169,6 +172,10 @@ public class BatteryMeterView extends LinearLayout implements
setClipChildren(false);
setClipToPadding(false);
Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
+
+ // Needed for PorderDuff.Mode.CLEAR operations to work properly, but redraws don't happen
+ // enough to justify a hardware layer.
+ setLayerType(LAYER_TYPE_SOFTWARE, null);
}
public void setForceShowPercent(boolean show) {
@@ -243,9 +250,11 @@ public class BatteryMeterView extends LinearLayout implements
if (mUseWallpaperTextColors) {
updateColors(
Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor),
- Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary));
+ Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary),
+ Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
} else {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
+ mNonAdaptedSingleToneColor);
}
}
@@ -258,10 +267,14 @@ public class BatteryMeterView extends LinearLayout implements
Utils.getThemeAttr(context, R.attr.darkIconTheme));
Context dualToneLightTheme = new ContextThemeWrapper(context,
Utils.getThemeAttr(context, R.attr.lightIconTheme));
+ mDarkModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
+ R.attr.singleToneColor);
mDarkModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.backgroundColor);
mDarkModeFillColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.fillColor);
+ mLightModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
+ R.attr.singleToneColor);
mLightModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
R.attr.backgroundColor);
mLightModeFillColor = Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor);
@@ -303,8 +316,8 @@ public class BatteryMeterView extends LinearLayout implements
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- mDrawable.setBatteryLevel(level);
mDrawable.setCharging(pluggedIn);
+ mDrawable.setBatteryLevel(level);
mCharging = pluggedIn;
mLevel = level;
updatePercentText();
@@ -315,7 +328,7 @@ public class BatteryMeterView extends LinearLayout implements
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
- mDrawable.setPowerSave(isPowerSave);
+ mDrawable.setPowerSaveEnabled(isPowerSave);
}
private TextView loadPercentView() {
@@ -406,21 +419,24 @@ public class BatteryMeterView extends LinearLayout implements
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+ mNonAdaptedSingleToneColor = getColorForDarkIntensity(
+ intensity, mLightModeSingleToneColor, mDarkModeSingleToneColor);
mNonAdaptedForegroundColor = getColorForDarkIntensity(
intensity, mLightModeFillColor, mDarkModeFillColor);
mNonAdaptedBackgroundColor = getColorForDarkIntensity(
intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
if (!mUseWallpaperTextColors) {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
+ mNonAdaptedSingleToneColor);
}
}
- private void updateColors(int foregroundColor, int backgroundColor) {
- mDrawable.setColors(foregroundColor, backgroundColor);
- mTextColor = foregroundColor;
+ private void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
+ mDrawable.setColors(foregroundColor, backgroundColor, singleToneColor);
+ mTextColor = singleToneColor;
if (mBatteryPercentView != null) {
- mBatteryPercentView.setTextColor(foregroundColor);
+ mBatteryPercentView.setTextColor(singleToneColor);
}
}
@@ -429,7 +445,7 @@ public class BatteryMeterView extends LinearLayout implements
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- String powerSave = mDrawable == null ? null : mDrawable.getPowerSave() + "";
+ String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
pw.println(" BatteryMeterView:");
pw.println(" mDrawable.getPowerSave: " + powerSave);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index b635033ea771..603b3b9766d9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -39,6 +39,7 @@ import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -48,7 +49,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.StatsLog;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageButton;
@@ -189,6 +189,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mPointerView.setBackground(triangleDrawable);
FrameLayout viewWrapper = findViewById(R.id.header_permission_wrapper);
+ viewWrapper.setBackground(createHeaderPermissionBackground(bgColor));
+
LayoutTransition transition = new LayoutTransition();
transition.setDuration(200);
@@ -204,6 +206,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
viewWrapper.setLayoutTransition(transition);
viewWrapper.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
+
mHeaderHeight = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_expanded_header_height);
mPermissionHeight = getContext().getResources().getDimensionPixelSize(
@@ -243,7 +246,10 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
if (!mShowOnTop) {
removeView(mPointerView);
if (mUseFooter) {
+ View divider = findViewById(R.id.divider);
+ viewWrapper.removeView(divider);
removeView(viewWrapper);
+ addView(divider);
addView(viewWrapper);
}
addView(mPointerView);
@@ -251,6 +257,25 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
}
/**
+ * Creates a background with corners rounded based on how the view is configured to display
+ */
+ private Drawable createHeaderPermissionBackground(int bgColor) {
+ TypedArray ta2 = getContext().obtainStyledAttributes(
+ new int[] {android.R.attr.dialogCornerRadius});
+ final float cr = ta2.getDimension(0, 0f);
+ ta2.recycle();
+
+ float[] radii = mUseFooter
+ ? new float[] {0, 0, 0, 0, cr, cr, cr, cr}
+ : new float[] {cr, cr, cr, cr, 0, 0, 0, 0};
+ GradientDrawable chromeBackground = new GradientDrawable();
+ chromeBackground.setShape(GradientDrawable.RECTANGLE);
+ chromeBackground.setCornerRadii(radii);
+ chromeBackground.setColor(bgColor);
+ return chromeBackground;
+ }
+
+ /**
* Sets the listener to notify when a bubble has been blocked.
*/
public void setOnBlockedListener(OnBubbleBlockedListener listener) {
@@ -491,23 +516,14 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
/**
* Removes and releases an ActivityView if one was previously created for this bubble.
*/
- public void destroyActivityView(ViewGroup tmpParent) {
+ public void destroyActivityView() {
if (mActivityView == null) {
return;
}
- if (!mActivityViewReady) {
- // release not needed, never initialized?
- mActivityView = null;
- return;
- }
- // HACK: release() will crash if the view is not attached.
- if (!isAttachedToWindow()) {
- mActivityView.setVisibility(View.GONE);
- tmpParent.addView(this);
+ if (mActivityViewReady) {
+ mActivityView.release();
}
-
- mActivityView.release();
- ((ViewGroup) getParent()).removeView(this);
+ removeView(mActivityView);
mActivityView = null;
mActivityViewReady = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 167bf47664e0..8235d8de3257 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -348,7 +348,7 @@ public class BubbleStackView extends FrameLayout {
// Remove it from the views
int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
- b.expandedView.destroyActivityView(this /* tmpParent */);
+ b.expandedView.destroyActivityView();
mBubbleContainer.removeView(b.iconView);
int bubbleCount = mBubbleContainer.getChildCount();
@@ -377,7 +377,7 @@ public class BubbleStackView extends FrameLayout {
public void stackDismissed() {
for (Bubble bubble : mBubbleData.getBubbles()) {
bubble.entry.setBubbleDismissed(true);
- bubble.expandedView.destroyActivityView(this /* tmpParent */);
+ bubble.expandedView.destroyActivityView();
}
mBubbleData.clear();
collapseStack();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 5353ee6c8ab3..06dbdbf1efa8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -17,11 +17,11 @@
package com.android.systemui.doze;
import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 325018227692..36e28dc0156d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -21,9 +21,9 @@ import android.app.Application;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 4d89a391a14f..6c4be0617043 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -17,12 +17,12 @@
package com.android.systemui.doze;
import android.annotation.MainThread;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.Preconditions;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 2d1dba6f79c8..77180f8cc07a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -30,6 +30,7 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
@@ -38,7 +39,8 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.plugins.SensorManagerPlugin;
@@ -60,7 +62,6 @@ public class DozeSensors {
private final Context mContext;
private final AlarmManager mAlarmManager;
private final SensorManager mSensorManager;
- private final TriggerSensor[] mSensors;
private final ContentResolver mResolver;
private final TriggerSensor mPickupSensor;
private final DozeParameters mDozeParameters;
@@ -68,10 +69,12 @@ public class DozeSensors {
private final WakeLock mWakeLock;
private final Consumer<Boolean> mProxCallback;
private final Callback mCallback;
+ @VisibleForTesting
+ protected final TriggerSensor[] mSensors;
private final Handler mHandler = new Handler();
private final ProxSensor mProxSensor;
-
+ private long mDebounceFrom;
public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
@@ -134,13 +137,21 @@ public class DozeSensors {
mConfig.wakeScreenGestureAvailable() && alwaysOn,
DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
false /* reports touch coordinates */,
- false /* touchscreen */),
+ false /* touchscreen */, mConfig.getWakeLockScreenDebounce()),
};
mProxSensor = new ProxSensor(policy);
mCallback = callback;
}
+ /**
+ * Temporarily disable some sensors to avoid turning on the device while the user is
+ * turning it off.
+ */
+ public void requestTemporaryDisable() {
+ mDebounceFrom = SystemClock.uptimeMillis();
+ }
+
private Sensor findSensorWithType(String type) {
return findSensorWithType(mSensorManager, type);
}
@@ -179,15 +190,6 @@ public class DozeSensors {
}
}
- public void reregisterAllSensors() {
- for (TriggerSensor s : mSensors) {
- s.setListening(false);
- }
- for (TriggerSensor s : mSensors) {
- s.setListening(true);
- }
- }
-
public void onUserSwitched() {
for (TriggerSensor s : mSensors) {
s.updateListener();
@@ -320,7 +322,8 @@ public class DozeSensors {
}
}
- private class TriggerSensor extends TriggerEventListener {
+ @VisibleForTesting
+ class TriggerSensor extends TriggerEventListener {
final Sensor mSensor;
final boolean mConfigured;
final int mPulseReason;
@@ -467,23 +470,25 @@ public class DozeSensors {
/**
* A Sensor that is injected via plugin.
*/
- private class PluginSensor extends TriggerSensor {
+ @VisibleForTesting
+ class PluginSensor extends TriggerSensor implements SensorManagerPlugin.SensorEventListener {
- private final SensorManagerPlugin.Sensor mPluginSensor;
- private final SensorManagerPlugin.SensorEventListener mTriggerEventListener = (event) -> {
- DozeLog.traceSensor(mContext, mPulseReason);
- mHandler.post(mWakeLock.wrap(() -> {
- if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
- mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
- event.getValues());
- }));
- };
+ final SensorManagerPlugin.Sensor mPluginSensor;
+ private long mDebounce;
PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+ this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
+ requiresTouchscreen, 0L /* debounce */);
+ }
+
+ PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
+ int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
+ long debounce) {
super(null, setting, configured, pulseReason, reportsTouchCoordinates,
requiresTouchscreen);
mPluginSensor = sensor;
+ mDebounce = debounce;
}
@Override
@@ -492,11 +497,11 @@ public class DozeSensors {
AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
&& !mRegistered) {
- asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener);
+ asyncSensorManager.registerPluginListener(mPluginSensor, this);
mRegistered = true;
if (DEBUG) Log.d(TAG, "registerPluginListener");
} else if (mRegistered) {
- asyncSensorManager.unregisterPluginListener(mPluginSensor, mTriggerEventListener);
+ asyncSensorManager.unregisterPluginListener(mPluginSensor, this);
mRegistered = false;
if (DEBUG) Log.d(TAG, "unregisterPluginListener");
}
@@ -524,6 +529,21 @@ public class DozeSensors {
}
return sb.append(']').toString();
}
+
+ @Override
+ public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
+ DozeLog.traceSensor(mContext, mPulseReason);
+ mHandler.post(mWakeLock.wrap(() -> {
+ final long now = SystemClock.uptimeMillis();
+ if (now < mDebounceFrom + mDebounce) {
+ if (DEBUG) Log.d(TAG, "onSensorEvent dropped: " + triggerEventToString(event));
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
+ mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
+ event.getValues());
+ }));
+ }
}
public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 70bf903cd712..b2f707f76c10 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -27,6 +27,7 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -34,7 +35,6 @@ import android.text.format.Formatter;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.Preconditions;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -143,8 +143,12 @@ public class DozeTriggers implements DozeMachine.Part {
if (isWakeDisplay) {
onWakeScreen(wakeEvent, mMachine.getState());
- } else if (isLongPress || isWakeLockScreen) {
+ } else if (isLongPress) {
requestPulse(pulseReason, sensorPerformedProxCheck);
+ } else if (isWakeLockScreen) {
+ if (wakeEvent) {
+ requestPulse(pulseReason, sensorPerformedProxCheck);
+ }
} else {
proximityCheckThenCall((result) -> {
if (result == ProximityCheck.RESULT_NEAR) {
@@ -228,14 +232,12 @@ public class DozeTriggers implements DozeMachine.Part {
if (mDockManager != null) {
mDockManager.addListener(mDockEventListener);
}
+ mDozeSensors.requestTemporaryDisable();
checkTriggersAtInit();
break;
case DOZE:
case DOZE_AOD:
mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
- if (oldState != DozeMachine.State.INITIALIZED) {
- mDozeSensors.reregisterAllSensors();
- }
mDozeSensors.setListening(true);
if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
onWakeScreen(false, newState);
@@ -250,6 +252,9 @@ public class DozeTriggers implements DozeMachine.Part {
mDozeSensors.setTouchscreenSensorsListening(false);
mDozeSensors.setProxListening(true);
break;
+ case DOZE_PULSE_DONE:
+ mDozeSensors.requestTemporaryDisable();
+ break;
case FINISH:
mBroadcastReceiver.unregister(mContext);
mDozeHost.removeCallback(mHostCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 66cfadf9d6e8..172746e2ffbe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -21,7 +21,6 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
-import static com.android.internal.telephony.IccCardConstants.State.READY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -95,7 +94,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
/**
* Mediates requests related to the keyguard. This includes queries about the
@@ -247,9 +245,6 @@ public class KeyguardViewMediator extends SystemUI {
// AOD is enabled and status bar is in AOD state.
private boolean mAodShowing;
- // display ids of the external display on which we have put a keyguard window
- private int[] mSecondaryDisplaysShowing;
-
/** Cached value of #isInputRestricted */
private boolean mInputRestricted;
@@ -687,13 +682,6 @@ public class KeyguardViewMediator extends SystemUI {
mCustomMessage = null;
return message;
}
-
- @Override
- public void onSecondaryDisplayShowingChanged(int[] displayIds) {
- synchronized (KeyguardViewMediator.this) {
- setShowingLocked(mShowing, mAodShowing, displayIds, false);
- }
- }
};
public void userActivity() {
@@ -722,7 +710,7 @@ public class KeyguardViewMediator extends SystemUI {
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
SYSTEMUI_PERMISSION, null /* scheduler */);
- mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, mViewMediatorCallback);
+ mKeyguardDisplayManager = new KeyguardDisplayManager(mContext);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -738,10 +726,10 @@ public class KeyguardViewMediator extends SystemUI {
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser()),
- mAodShowing, mSecondaryDisplaysShowing, true /* forceCallbacks */);
+ mAodShowing, true /* forceCallbacks */);
} else {
// The system's keyguard is disabled or missing.
- setShowingLocked(false, mAodShowing, mSecondaryDisplaysShowing, true);
+ setShowingLocked(false, mAodShowing, true);
}
mStatusBarKeyguardViewManager =
@@ -1764,12 +1752,10 @@ public class KeyguardViewMediator extends SystemUI {
playSound(mTrustedSoundId);
}
- private void updateActivityLockScreenState(boolean showing, boolean aodShowing,
- int[] secondaryDisplaysShowing) {
+ private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
mUiOffloadThread.submit(() -> {
try {
- ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing,
- secondaryDisplaysShowing);
+ ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
} catch (RemoteException e) {
}
});
@@ -1892,8 +1878,7 @@ public class KeyguardViewMediator extends SystemUI {
if (!mHiding) {
// Tell ActivityManager that we canceled the keyguardExitAnimation.
- setShowingLocked(mShowing, mAodShowing, mSecondaryDisplaysShowing,
- true /* force */);
+ setShowingLocked(mShowing, mAodShowing, true /* force */);
return;
}
mHiding = false;
@@ -2163,23 +2148,19 @@ public class KeyguardViewMediator extends SystemUI {
}
private void setShowingLocked(boolean showing, boolean aodShowing) {
- setShowingLocked(showing, aodShowing, mSecondaryDisplaysShowing,
- false /* forceCallbacks */);
+ setShowingLocked(showing, aodShowing, false /* forceCallbacks */);
}
- private void setShowingLocked(boolean showing, boolean aodShowing,
- int[] secondaryDisplaysShowing, boolean forceCallbacks) {
+ private void setShowingLocked(boolean showing, boolean aodShowing, boolean forceCallbacks) {
final boolean notifyDefaultDisplayCallbacks = showing != mShowing
|| aodShowing != mAodShowing || forceCallbacks;
- if (notifyDefaultDisplayCallbacks
- || !Arrays.equals(secondaryDisplaysShowing, mSecondaryDisplaysShowing)) {
+ if (notifyDefaultDisplayCallbacks) {
mShowing = showing;
mAodShowing = aodShowing;
- mSecondaryDisplaysShowing = secondaryDisplaysShowing;
if (notifyDefaultDisplayCallbacks) {
notifyDefaultDisplayCallbacks(showing);
}
- updateActivityLockScreenState(showing, aodShowing, secondaryDisplaysShowing);
+ updateActivityLockScreenState(showing, aodShowing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index cef1b6b1d93b..3140e6db2442 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -37,6 +37,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Size;
import android.view.IPinnedStackController;
+import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
@@ -206,7 +207,7 @@ public class PipTouchHandler {
mEnableDimissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
// Register the listener for input consumer touch events
- inputConsumerController.setTouchListener(this::handleTouchEvent);
+ inputConsumerController.setInputListener(this::handleTouchEvent);
inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
onRegistrationChanged(inputConsumerController.isRegistered());
}
@@ -370,11 +371,16 @@ public class PipTouchHandler {
mMovementBounds, true /* allowMenuTimeout */, willResizeMenu());
}
- private boolean handleTouchEvent(MotionEvent ev) {
+ private boolean handleTouchEvent(InputEvent inputEvent) {
+ // Skip any non motion events
+ if (!(inputEvent instanceof MotionEvent)) {
+ return true;
+ }
// Skip touch handling until we are bound to the controller
if (mPinnedStackController == null) {
return true;
}
+ MotionEvent ev = (MotionEvent) inputEvent;
// Update the touch state
mTouchState.onTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 75b8a056df1d..84a344648a39 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -42,14 +42,10 @@ class OngoingPrivacyDialog constructor(
private val iconSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_size)
- private val plusSize = context.resources.getDimensionPixelSize(
- R.dimen.ongoing_appops_dialog_app_plus_size)
private val iconColor = context.resources.getColor(
com.android.internal.R.color.text_color_primary, context.theme)
- private val plusColor: Int
private val iconMargin = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_margin)
- private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
private val iconFactory = IconDrawableFactory.newInstance(context, true)
private var dismissDialog: (() -> Unit)? = null
private val appsAndTypes = dialogBuilder.appsAndTypes
@@ -57,13 +53,6 @@ class OngoingPrivacyDialog constructor(
{ it.second.min() },
{ it.first }))
- init {
- val a = context.theme.obtainStyledAttributes(
- intArrayOf(com.android.internal.R.attr.colorAccent))
- plusColor = a.getColor(0, 0)
- a.recycle()
- }
-
fun createDialog(): Dialog {
val builder = AlertDialog.Builder(context).apply {
setPositiveButton(R.string.ongoing_privacy_dialog_ok, null)
@@ -96,33 +85,9 @@ class OngoingPrivacyDialog constructor(
val numItems = appsAndTypes.size
for (i in 0..(numItems - 1)) {
- if (i >= MAX_ITEMS) break
val item = appsAndTypes[i]
addAppItem(appsList, item.first, item.second, dialogBuilder.types.size > 1)
}
-
- if (numItems > MAX_ITEMS) {
- val overflow = contentView.findViewById(R.id.overflow) as LinearLayout
- overflow.visibility = View.VISIBLE
- val overflowText = overflow.findViewById(R.id.app_name) as TextView
- overflowText.text = context.resources.getQuantityString(
- R.plurals.ongoing_privacy_dialog_overflow_text,
- numItems - MAX_ITEMS,
- numItems - MAX_ITEMS
- )
- val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
- val lp = overflowPlus.layoutParams.apply {
- height = plusSize
- width = plusSize
- }
- overflowPlus.layoutParams = lp
- overflowPlus.apply {
- val plus = context.getDrawable(R.drawable.plus)
- imageTintList = ColorStateList.valueOf(plusColor)
- setImageDrawable(plus)
- }
- }
-
return contentView
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index a6e48f8835c7..3f581c4de5fb 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -18,6 +18,8 @@ import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import android.util.IconDrawableFactory
import com.android.systemui.R
typealias Privacy = PrivacyType
@@ -46,14 +48,21 @@ data class PrivacyApplication(val packageName: String, val uid: Int, val context
private val applicationInfo: ApplicationInfo? by lazy {
try {
- context.packageManager.getApplicationInfo(packageName, 0)
+ val userHandle = UserHandle.getUserHandleForUid(uid)
+ context.createPackageContextAsUser(packageName, 0, userHandle).getPackageManager()
+ .getApplicationInfo(packageName, 0)
} catch (_: PackageManager.NameNotFoundException) {
null
}
}
val icon: Drawable by lazy {
applicationInfo?.let {
- context.packageManager.getApplicationIcon(it)
+ try {
+ val iconFactory = IconDrawableFactory.newInstance(context, true)
+ iconFactory.getBadgedIcon(it, UserHandle.getUserId(uid))
+ } catch (_: Exception) {
+ null
+ }
} ?: context.getDrawable(android.R.drawable.sym_def_app_icon)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 7f76900bba21..c664a2090c04 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -15,14 +15,11 @@
*/
package com.android.systemui.qs.tiles;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.qs.QSHost;
@@ -41,6 +38,8 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
private boolean mCharging;
private boolean mPluggedIn;
+ private Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_battery_saver);
+
@Inject
public BatterySaverTile(QSHost host, BatteryController batteryController) {
super(host);
@@ -84,9 +83,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
protected void handleUpdateState(BooleanState state, Object arg) {
state.state = mPluggedIn ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- BatterySaverIcon bsi = new BatterySaverIcon();
- bsi.mState = state.state;
- state.icon = bsi;
+ state.icon = mIcon;
state.label = mContext.getString(R.string.battery_detail_switch_title);
state.contentDescription = state.label;
state.value = mPowerSave;
@@ -106,48 +103,4 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
mPowerSave = isPowerSave;
refreshState(null);
}
-
- public static class BatterySaverIcon extends Icon {
- private int mState;
-
- @Override
- public Drawable getDrawable(Context context) {
- BatterySaverDrawable b =
- new BatterySaverDrawable(context, QSTileImpl.getColorForState(context, mState));
- b.mState = mState;
- final int pad = context.getResources()
- .getDimensionPixelSize(R.dimen.qs_tile_divider_height);
- b.setPadding(pad, pad, pad, pad);
- return b;
- }
- }
-
- private static class BatterySaverDrawable extends BatteryMeterDrawableBase {
- private int mState;
- private static final int MAX_BATTERY = 100;
-
- BatterySaverDrawable(Context context, int frameColor) {
- super(context, frameColor);
- // Show as full so it's always uniform color
- super.setBatteryLevel(MAX_BATTERY);
- setPowerSave(true);
- setCharging(false);
- setPowerSaveAsColorError(false);
- mPowerSaveAsColorError = true;
- mFramePaint.setColor(0);
- mPowersavePaint.setColor(frameColor);
- mFramePaint.setStrokeWidth(mPowersavePaint.getStrokeWidth());
- mPlusPaint.setColor(frameColor);
- }
-
- @Override
- protected int batteryColorForLevel(int level) {
- return 0;
- }
-
- @Override
- public void setBatteryLevel(int val) {
- // Don't change the actual level, otherwise this won't draw correctly
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index e1becdbb42a6..c587a39f49e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -25,7 +25,11 @@ import android.content.Intent;
import android.content.res.Resources;
import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -188,7 +192,8 @@ public class CellularTile extends QSTileImpl<SignalState> {
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
} else if (mobileDataEnabled) {
state.state = Tile.STATE_ACTIVE;
- state.secondaryLabel = getMobileDataSubscriptionName(cb);
+ state.secondaryLabel = appendMobileDataType(getMobileDataSubscriptionName(cb),
+ cb.dataContentDescription);
} else {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = r.getString(R.string.cell_data_off);
@@ -207,6 +212,18 @@ public class CellularTile extends QSTileImpl<SignalState> {
state.contentDescription = state.label + ", " + contentDescriptionSuffix;
}
+ private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) {
+ if (TextUtils.isEmpty(dataType)) {
+ return current;
+ }
+ SpannableString type = new SpannableString(dataType);
+ SpannableStringBuilder builder = new SpannableStringBuilder(current);
+ builder.append(" ");
+ builder.append(type, new TextAppearanceSpan(mContext, R.style.TextAppearance_RATBadge),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return builder;
+ }
+
private CharSequence getMobileDataSubscriptionName(CallbackInfo cb) {
if (cb.roaming && !TextUtils.isEmpty(cb.dataSubscriptionName)) {
String roaming = mContext.getString(R.string.data_connection_roaming);
@@ -232,6 +249,7 @@ public class CellularTile extends QSTileImpl<SignalState> {
private static final class CallbackInfo {
boolean airplaneModeEnabled;
CharSequence dataSubscriptionName;
+ CharSequence dataContentDescription;
boolean activityIn;
boolean activityOut;
boolean noSim;
@@ -250,6 +268,7 @@ public class CellularTile extends QSTileImpl<SignalState> {
return;
}
mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
+ mInfo.dataContentDescription = (description != null) ? typeContentDescription : null;
mInfo.activityIn = activityIn;
mInfo.activityOut = activityOut;
mInfo.roaming = roaming;
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 c9be2c8f6703..007c50c8765d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -25,6 +25,8 @@ import com.android.systemui.Dependency;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -42,6 +44,7 @@ public class AutoTileManager {
public static final String INVERSION = "inversion";
public static final String WORK = "work";
public static final String NIGHT = "night";
+ public static final String CAST = "cast";
private final Context mContext;
private final QSTileHost mHost;
@@ -51,6 +54,7 @@ public class AutoTileManager {
private final DataSaverController mDataSaverController;
private final ManagedProfileController mManagedProfileController;
private final NightDisplayListener mNightDisplayListener;
+ private final CastController mCastController;
@Inject
public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
@@ -58,7 +62,8 @@ public class AutoTileManager {
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
- NightDisplayListener nightDisplayListener) {
+ NightDisplayListener nightDisplayListener,
+ CastController castController) {
mAutoTracker = autoAddTracker;
mContext = context;
mHost = host;
@@ -67,6 +72,7 @@ public class AutoTileManager {
mDataSaverController = dataSaverController;
mManagedProfileController = managedProfileController;
mNightDisplayListener = nightDisplayListener;
+ mCastController = castController;
if (!mAutoTracker.isAdded(HOTSPOT)) {
hotspotController.addCallback(mHotspotCallback);
}
@@ -95,6 +101,9 @@ public class AutoTileManager {
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
nightDisplayListener.setCallback(mNightDisplayCallback);
}
+ if (!mAutoTracker.isAdded(CAST)) {
+ castController.addCallback(mCastCallback);
+ }
}
public void destroy() {
@@ -108,6 +117,7 @@ public class AutoTileManager {
if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
mNightDisplayListener.setCallback(null);
}
+ mCastController.removeCallback(mCastCallback);
}
public void unmarkTileAsAutoAdded(String tabSpec) {
@@ -181,4 +191,27 @@ public class AutoTileManager {
mHandler.post(() -> mNightDisplayListener.setCallback(null));
}
};
+
+ @VisibleForTesting
+ final CastController.Callback mCastCallback = new CastController.Callback() {
+ @Override
+ public void onCastDevicesChanged() {
+ if (mAutoTracker.isAdded(CAST)) return;
+
+ boolean isCasting = false;
+ for (CastDevice device : mCastController.getCastDevices()) {
+ if (device.state == CastDevice.STATE_CONNECTED
+ || device.state == CastDevice.STATE_CONNECTING) {
+ isCasting = true;
+ break;
+ }
+ }
+
+ if (isCasting) {
+ mHost.addTile(CAST);
+ mAutoTracker.setTileAdded(CAST);
+ mHandler.post(() -> mCastController.removeCallback(mCastCallback));
+ }
+ }
+ };
}
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 10497734d0b1..a17e04259fe3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -26,7 +27,6 @@ import android.util.MathUtils;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index e1a77b00f3ca..ce69a489737a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -246,7 +246,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
private boolean isExpanded(State state) {
return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
|| state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
- || state.headsUpShowing || state.bubblesShowing
+ || state.headsUpShowing || state.bubblesShowing || state.assistShowing
|| state.scrimsVisibility != ScrimController.VISIBILITY_FULLY_TRANSPARENT);
}
@@ -490,6 +490,21 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
}
/**
+ * Sets whether assist UI is showing on the screen.
+ */
+ public void setAssistShowing(boolean assistShowing) {
+ mCurrentState.assistShowing = assistShowing;
+ apply(mCurrentState);
+ }
+
+ /**
+ * The assist UI showing state for the status bar.
+ */
+ public boolean getAssistShowing() {
+ return mCurrentState.assistShowing;
+ }
+
+ /**
* Sets if there is a bubble being expanded on the screen.
*/
public void setBubbleExpanded(boolean bubbleExpanded) {
@@ -558,6 +573,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
boolean notTouchable;
boolean bubblesShowing;
boolean bubbleExpanded;
+ boolean assistShowing;
/**
* The {@link StatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index ad4ba75d6569..50c4fac31bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -29,14 +29,18 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.DisplayCutout;
+import android.view.GestureDetector;
import android.view.InputDevice;
import android.view.InputQueue;
import android.view.KeyEvent;
@@ -63,16 +67,23 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+/**
+ * Combined status bar and notification panel view. Also holding backdrop and scrims.
+ */
public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "StatusBarWindowView";
public static final boolean DEBUG = StatusBar.DEBUG;
+ private final GestureDetector mGestureDetector;
+ private final StatusBarStateController mStatusBarStateController;
+ private boolean mDoubleTapEnabled;
+ private boolean mSingleTapEnabled;
private DragDownHelper mDragDownHelper;
- private DoubleTapHelper mDoubleTapHelper;
private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
private View mBrightnessMirror;
@@ -95,8 +106,37 @@ public class StatusBarWindowView extends FrameLayout {
private boolean mTouchActive;
private boolean mExpandAnimationRunning;
private boolean mExpandAnimationPending;
- private final StatusBarStateController
- mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+
+ private final GestureDetector.SimpleOnGestureListener mGestureListener =
+ new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ if (mSingleTapEnabled) {
+ mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
+ "SINGLE_TAP");
+ }
+ return mSingleTapEnabled;
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ if (mDoubleTapEnabled) {
+ mService.wakeUpIfDozing(SystemClock.uptimeMillis(), StatusBarWindowView.this,
+ "DOUBLE_TAP");
+ }
+ return mDoubleTapEnabled;
+ }
+ };
+ private final TunerService.Tunable mTunable = (key, newValue) -> {
+ AmbientDisplayConfiguration configuration = new AmbientDisplayConfiguration(mContext);
+ switch (key) {
+ case Settings.Secure.DOZE_DOUBLE_TAP_GESTURE:
+ mDoubleTapEnabled = configuration.doubleTapGestureEnabled(UserHandle.USER_CURRENT);
+ break;
+ case Settings.Secure.DOZE_TAP_SCREEN_GESTURE:
+ mSingleTapEnabled = configuration.tapGestureEnabled(UserHandle.USER_CURRENT);
+ }
+ };
/**
* If set to true, the current gesture started below the notch and we need to dispatch touch
@@ -110,10 +150,11 @@ public class StatusBarWindowView extends FrameLayout {
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
mFalsingManager = FalsingManager.getInstance(context);
- mDoubleTapHelper = new DoubleTapHelper(this, active -> {}, () -> {
- mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this, "DOUBLE_TAP");
- return true;
- }, null, null);
+ mGestureDetector = new GestureDetector(context, mGestureListener);
+ mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+ Dependency.get(TunerService.class).addTunable(mTunable,
+ Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
+ Settings.Secure.DOZE_TAP_SCREEN_GESTURE);
}
@Override
@@ -306,6 +347,7 @@ public class StatusBarWindowView extends FrameLayout {
return false;
}
mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
+ mGestureDetector.onTouchEvent(ev);
if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
// Disallow new pointers while the brightness mirror is visible. This is so that you
// can't touch anything other than the brightness slider while the mirror is showing
@@ -366,7 +408,6 @@ public class StatusBarWindowView extends FrameLayout {
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = false;
if (mService.isDozing()) {
- mDoubleTapHelper.onTouchEvent(ev);
handled = !mService.isPulsing();
}
if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
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 b22150b2f507..8b81585836dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -57,13 +57,17 @@ public final class SmartReplyConstants extends ContentObserver {
private final int mDefaultMinNumSystemGeneratedReplies;
private final int mDefaultMaxNumActions;
- private boolean mEnabled;
- private boolean mRequiresTargetingP;
- private int mMaxSqueezeRemeasureAttempts;
- private boolean mEditChoicesBeforeSending;
- private boolean mShowInHeadsUp;
- private int mMinNumSystemGeneratedReplies;
- private int mMaxNumActions;
+ // These fields are updated on the UI thread but can be accessed on both the UI thread and
+ // background threads. We use the volatile keyword here instead of synchronization blocks since
+ // we only care about variable updates here being visible to other threads (and not for example
+ // whether the variables we are reading were updated in the same go).
+ private volatile boolean mEnabled;
+ private volatile boolean mRequiresTargetingP;
+ private volatile int mMaxSqueezeRemeasureAttempts;
+ private volatile boolean mEditChoicesBeforeSending;
+ private volatile boolean mShowInHeadsUp;
+ private volatile int mMinNumSystemGeneratedReplies;
+ private volatile int mMaxNumActions;
private final Context mContext;
private final KeyValueListParser mParser = new KeyValueListParser(',');
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index ecf1784e66c4..0070dcf9a604 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -19,6 +19,7 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
@@ -29,7 +30,6 @@ import android.view.MenuItem;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragment;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f56727f3e0fa..ffd8206ca887 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -25,6 +25,7 @@ import static android.media.AudioManager.STREAM_ALARM;
import static android.media.AudioManager.STREAM_MUSIC;
import static android.media.AudioManager.STREAM_RING;
import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -441,6 +442,7 @@ public class VolumeDialogImpl implements VolumeDialog {
public void initRingerH() {
if (mRingerIcon != null) {
+ mRingerIcon.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
mRingerIcon.setOnClickListener(v -> {
Prefs.putBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, true);
final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index e91a7e9bfcb6..0114075b1e65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -82,6 +83,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
new Handler(mTestableLooper.getLooper()));
+ mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
+ mTunerService = mDependency.injectMockDependency(TunerService.class);
+ mFragmentService = mDependency.injectMockDependency(FragmentService.class);
mStatusBar = mock(StatusBar.class);
mWindowManager = mock(WindowManager.class);
@@ -93,12 +97,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
when(mWindowManager.getDefaultDisplay()).thenReturn(display);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
- mFragmentService = mDependency.injectMockDependency(FragmentService.class);
mFragmentHostManager = mock(FragmentHostManager.class);
when(mFragmentService.getFragmentHostManager(any())).thenReturn(mFragmentHostManager);
- mTunerService = mDependency.injectMockDependency(TunerService.class);
-
mScreenDecorations = new ScreenDecorations() {
@Override
@@ -126,8 +127,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
};
mScreenDecorations.mContext = mContext;
mScreenDecorations.mComponents = mContext.getComponents();
-
- mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
+ reset(mTunerService);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
index 45342d4bc3a9..6807c22175ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
@@ -18,12 +18,12 @@ package com.android.systemui.doze;
import static junit.framework.TestCase.assertEquals;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index e4558df962e3..9438cbb6ebcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -16,12 +16,13 @@
package com.android.systemui.doze;
+import android.hardware.display.AmbientDisplayConfiguration;
+
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.statusbar.phone.DozeParameters;
import org.mockito.Answers;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 0fc0953f333e..23ff3d483599 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -35,7 +36,6 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 5a6200f5f80a..f972508c0375 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -38,11 +38,11 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.wakelock.WakeLockFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
new file mode 100644
index 000000000000..463a6e63835e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.doze;
+
+import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.AsyncSensorManager;
+import com.android.systemui.util.wakelock.WakeLock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class DozeSensorsTest extends SysuiTestCase {
+
+ @Mock
+ private AlarmManager mAlarmManager;
+ @Mock
+ private AsyncSensorManager mSensorManager;
+ @Mock
+ private DozeParameters mDozeParameters;
+ @Mock
+ private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+ @Mock
+ private WakeLock mWakeLock;
+ @Mock
+ private DozeSensors.Callback mCallback;
+ @Mock
+ private Consumer<Boolean> mProxCallback;
+ @Mock
+ private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
+ private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
+ private TestableLooper mTestableLooper;
+ private DozeSensors mDozeSensors;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+ when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
+ when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ }).when(mWakeLock).wrap(any(Runnable.class));
+ mDozeSensors = new TestableDozeSensors();
+ }
+
+ @Test
+ public void testSensorDebounce() {
+ mDozeSensors.setListening(true);
+
+ mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
+ mTestableLooper.processAllMessages();
+ verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+ anyBoolean(), anyFloat(), anyFloat(), eq(null));
+
+ mDozeSensors.requestTemporaryDisable();
+ reset(mCallback);
+ mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
+ mTestableLooper.processAllMessages();
+ verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+ anyBoolean(), anyFloat(), anyFloat(), eq(null));
+ }
+
+ private class TestableDozeSensors extends DozeSensors {
+
+ TestableDozeSensors() {
+ super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
+ mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback,
+ mAlwaysOnDisplayPolicy);
+ for (TriggerSensor sensor : mSensors) {
+ if (sensor instanceof PluginSensor
+ && ((PluginSensor) sensor).mPluginSensor.getType()
+ == TYPE_WAKE_LOCK_SCREEN) {
+ mWakeLockScreenListener = (PluginSensor) sensor;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index cdac7c979c55..ca373478f33c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.Instrumentation;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -34,7 +35,6 @@ import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index f3740c4d51d0..87699b816c07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -31,6 +32,8 @@ import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -40,6 +43,9 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
+import java.util.Set;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -47,6 +53,7 @@ public class AutoTileManagerTest extends SysuiTestCase {
@Mock private QSTileHost mQsTileHost;
@Mock private AutoAddTracker mAutoAddTracker;
+ @Mock private CastController mCastController;
private AutoTileManager mAutoTileManager;
@@ -58,7 +65,8 @@ public class AutoTileManagerTest extends SysuiTestCase {
mock(HotspotController.class),
mock(DataSaverController.class),
mock(ManagedProfileController.class),
- mock(NightDisplayListener.class));
+ mock(NightDisplayListener.class),
+ mCastController);
}
@Test
@@ -108,4 +116,24 @@ public class AutoTileManagerTest extends SysuiTestCase {
ColorDisplayManager.AUTO_MODE_DISABLED);
verify(mQsTileHost, never()).addTile("night");
}
+
+ private static Set<CastDevice> buildFakeCastDevice(boolean isCasting) {
+ CastDevice cd = new CastDevice();
+ cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
+ return Collections.singleton(cd);
+ }
+
+ @Test
+ public void castTileAdded_whenDeviceIsCasting() {
+ doReturn(buildFakeCastDevice(true)).when(mCastController).getCastDevices();
+ mAutoTileManager.mCastCallback.onCastDevicesChanged();
+ verify(mQsTileHost).addTile("cast");
+ }
+
+ @Test
+ public void castTileNotAdded_whenDeviceIsNotCasting() {
+ doReturn(buildFakeCastDevice(false)).when(mCastController).getCastDevices();
+ mAutoTileManager.mCastCallback.onCastDevicesChanged();
+ verify(mQsTileHost, never()).addTile("cast");
+ }
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 0084b536f467..365c6b4d16ee 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7017,6 +7017,54 @@ message MetricsEvent {
// OS: Q
ACTION_SWITCH_SHARE_PROFILE = 1661;
+ // ACTION: Show Contextual homepage, log latency in loading cards
+ ACTION_CONTEXTUAL_HOME_SHOW = 1662;
+
+ // ACTION: Contextual card displays
+ ACTION_CONTEXTUAL_CARD_SHOW = 1663;
+
+ // ACTION: Contextual cards are eligible to be shown, but don't rank high
+ ACTION_CONTEXTUAL_CARD_NOT_SHOW = 1664;
+
+ // ACTION: Settings > long press a card, and click dismiss
+ // Contextual card is dismissed
+ ACTION_CONTEXTUAL_CARD_DISMISS = 1665;
+
+ // ACTION: Settings > click a card
+ // Contextual card is clicked
+ ACTION_CONTEXTUAL_CARD_CLICK = 1666;
+
+ // Mapping: go/at-mapping
+ PAGE_ATSSI = 1667;
+
+ PAGE_ATSII = 1668;
+
+ PAGE_ATUS = 1669;
+
+ PAGE_ATSSP = 1670;
+
+ PAGE_ATSAP = 1671;
+
+ PAGE_ATSCP = 1672;
+
+ PAGE_ATHNP = 1673;
+
+ ACTION_ATSG = 1674;
+
+ ACTION_ATPG = 1675;
+
+ ACTION_ATCLPB = 1676;
+
+ ACTION_ATCGIB = 1677;
+
+ ACTION_ATCPAB = 1678;
+
+ ACTION_ATCSAUC = 1679;
+
+ ACTION_ATCSCUC = 1680;
+
+ ACTION_ATCHNUC = 1681;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 5fa7766ea510..7bf37ff379c9 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -524,6 +524,9 @@ message WifiLog {
// Link Probe metrics
optional LinkProbeStats link_probe_stats = 139;
+
+ // List of NetworkSelectionExperimentDecisions stats for each experiment
+ repeated NetworkSelectionExperimentDecisions network_selection_experiment_decisions_list = 140;
}
// Information that gets logged for every WiFi connection.
@@ -651,6 +654,39 @@ message ConnectionEvent {
HLF_UNWANTED = 4;
}
+ // Entity that recommended connecting to this network.
+ enum ConnectionNominator {
+ // Unknown nominator
+ NOMINATOR_UNKNOWN = 0;
+
+ // User selected network manually
+ NOMINATOR_MANUAL = 1;
+
+ // Saved network
+ NOMINATOR_SAVED = 2;
+
+ // Suggestion API
+ NOMINATOR_SUGGESTION = 3;
+
+ // Passpoint
+ NOMINATOR_PASSPOINT = 4;
+
+ // Carrier suggestion
+ NOMINATOR_CARRIER = 5;
+
+ // External scorer
+ NOMINATOR_EXTERNAL_SCORED = 6;
+
+ // Netrec
+ NOMINATOR_NETREC = 7;
+
+ // User connected choice override
+ NOMINATOR_SAVED_USER_CONNECT_CHOICE = 8;
+
+ // Open Network Available Pop-up
+ NOMINATOR_OPEN_NETWORK_AVAILABLE = 9;
+ }
+
// Start time of the connection.
optional int64 start_time_millis = 1;// [(datapol.semantic_type) = ST_TIMESTAMP];
@@ -680,6 +716,12 @@ message ConnectionEvent {
// Connection is using locally generated random MAC address.
optional bool use_randomized_mac = 10 [default = false];
+
+ // Who chose to connect.
+ optional ConnectionNominator connection_nominator = 11;
+
+ // The currently running network selector when this connection event occurred.
+ optional int32 network_selector_experiment_id = 12;
}
// Number of occurrences of a specific RSSI poll rssi value
@@ -2100,6 +2142,8 @@ message GroupEvent {
// Easy Connect (DPP)
message WifiDppLog {
+ reserved 6;
+
// Number of Configurator-Initiator requests
optional int32 num_dpp_configurator_initiator_requests = 1;
@@ -2116,7 +2160,7 @@ message WifiDppLog {
repeated DppFailureStatusHistogramBucket dpp_failure_code = 5;
// Easy Connect (DPP) operation time bucket
- repeated HistogramBucket dpp_operation_time = 6;
+ repeated HistogramBucketInt32 dpp_operation_time = 7;
// Histogram bucket for Wi-Fi DPP configurator success
message DppConfiguratorSuccessStatusHistogramBucket {
@@ -2136,18 +2180,6 @@ message WifiDppLog {
optional int32 count = 2;
}
- // Histogram bucket for Wi-Fi DPP logs. Range is [start, end)
- message HistogramBucket {
- // lower range of the bucket (inclusive)
- optional int32 start = 1;
-
- // upper range of the bucket (exclusive)
- optional int32 end = 2;
-
- // number of samples in the bucket
- optional int32 count = 3;
- }
-
enum DppConfiguratorSuccessCode {
// Unknown success code
EASY_CONNECT_EVENT_SUCCESS_UNKNOWN = 0;
@@ -2286,3 +2318,26 @@ message LinkProbeStats {
// Counts the occurrences of error codes for failed link probes.
repeated LinkProbeFailureReasonCount failure_reason_counts = 8;
}
+
+// Stores the decisions that were made by a experiment when compared against another experiment
+message NetworkSelectionExperimentDecisions {
+ // the id of one experiment
+ optional int32 experiment1_id = 1;
+
+ // the id of the other experiment
+ optional int32 experiment2_id = 2;
+
+ // Counts occurrences of the number of network choices there were when experiment1 makes the
+ // same network selection as experiment2.
+ // The keys are the number of network choices, and the values are the number of occurrences of
+ // this number of network choices when exp1 and exp2 make the same network selection.
+ repeated MapEntryInt32Int32 same_selection_num_choices_counter = 3;
+
+ // Counts occurrences of the number of network choices there were when experiment1 makes the
+ // same network selection as experiment2.
+ // The keys are the number of network choices, and the values are the number of occurrences of
+ // this number of network choices when exp1 and exp2 make different network selections.
+ // Note that it is possible for the network selection to be different even when there only exists
+ // a single network choice, since choosing not to connect to that network is a valid choice.
+ repeated MapEntryInt32Int32 different_selection_num_choices_counter = 4;
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1cca813ece25..245e2c990ee3 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -70,6 +70,7 @@ import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -109,6 +110,8 @@ public final class AutofillManagerService
private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
+ private static final int DEFAULT_AUGMENTED_AUTOFILL_REQUEST_TIMEOUT_MILLIS = 5_000;
+
/**
* Maximum number of partitions that can be allowed in a session.
*
@@ -162,6 +165,11 @@ public final class AutofillManagerService
@GuardedBy("mLock")
private int mSupportedSmartSuggestionModes;
+ @GuardedBy("mLock")
+ int mAugmentedServiceIdleUnbindTimeoutMs;
+ @GuardedBy("mLock")
+ int mAugmentedServiceRequestTimeoutMs;
+
public AutofillManagerService(Context context) {
super(context,
new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -171,12 +179,12 @@ public final class AutofillManagerService
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
ActivityThread.currentApplication().getMainExecutor(),
- (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value));
+ (namespace, key, value) -> onDeviceConfigChange(key, value));
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
setMaxVisibleDatasetsFromSettings();
- setSmartSuggestionModesFromDeviceConfig();
+ setDeviceConfigProperties();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -227,6 +235,18 @@ public final class AutofillManagerService
}
}
+ private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
+ switch (key) {
+ case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
+ case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
+ case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
+ setDeviceConfigProperties();
+ break;
+ default:
+ Slog.i(mTag, "Ignoring change on " + key);
+ }
+ }
+
@Override // from AbstractMasterSystemService
protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
@@ -457,27 +477,24 @@ public final class AutofillManagerService
}
}
- private void setSmartSuggestionModesFromDeviceConfig() {
- final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL,
- AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES);
- setSmartSuggestionModesFromDeviceConfig(value);
- }
-
- private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) {
- if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value);
- final int flags;
- if (value == null) {
- flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
- } else {
- try {
- flags = Integer.parseInt(value);
- } catch (Exception e) {
- Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value);
- return;
- }
- }
+ private void setDeviceConfigProperties() {
synchronized (mLock) {
- mSupportedSmartSuggestionModes = flags;
+ mAugmentedServiceIdleUnbindTimeoutMs = Helper.getIntDeviceConfigProperty(
+ AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT,
+ (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
+ mAugmentedServiceRequestTimeoutMs = Helper.getIntDeviceConfigProperty(
+ AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT,
+ DEFAULT_AUGMENTED_AUTOFILL_REQUEST_TIMEOUT_MILLIS);
+ mSupportedSmartSuggestionModes = Helper.getIntDeviceConfigProperty(
+ AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES,
+ AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM);
+ if (verbose) {
+ Slog.v(mTag, "setDeviceConfigProperties(): "
+ + "augmentedIdleTimeout=" + mAugmentedServiceIdleUnbindTimeoutMs
+ + ", augmentedRequestTimeout=" + mAugmentedServiceRequestTimeoutMs
+ + ", smartSuggestionMode="
+ + getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
+ }
}
}
@@ -1280,6 +1297,10 @@ public final class AutofillManagerService
pw.print("Smart Suggestion modes: ");
pw.println(getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
}
+ pw.print("Augmented Service Idle Unbind Timeout: ");
+ pw.println(mAugmentedServiceIdleUnbindTimeoutMs);
+ pw.print("Augmented Service Request Timeout: ");
+ pw.println(mAugmentedServiceRequestTimeoutMs);
if (showHistory) {
pw.println(); pw.println("Requests history:"); pw.println();
mRequestsHistory.reverseDump(fd, pw, args);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index b6d5b3de4c2d..3f33813ff4e7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -98,7 +98,7 @@ final class AutofillManagerServiceImpl
private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
/** Minimum interval to prune abandoned sessions */
- private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
+ private static final int MAX_ABANDONED_SESSION_MILLIS = 30_000;
private final AutoFillUI mUi;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
@@ -1087,7 +1087,9 @@ final class AutofillManagerServiceImpl
}
mRemoteAugmentedAutofillService = null;
}
- }, mMaster.isInstantServiceAllowed(), mMaster.verbose);
+ }, mMaster.isInstantServiceAllowed(), mMaster.verbose,
+ mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
+ mMaster.mAugmentedServiceRequestTimeoutMs);
}
return mRemoteAugmentedAutofillService;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 3c0da7d2d388..d300bf210e8a 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -22,9 +22,11 @@ import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.content.ComponentName;
import android.metrics.LogMaker;
+import android.provider.DeviceConfig;
import android.service.autofill.Dataset;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.view.WindowManager;
import android.view.autofill.AutofillId;
@@ -205,6 +207,21 @@ public final class Helper {
}
}
+ /**
+ * Gets the value of a device config property from the Autofill namespace.
+ */
+ static int getIntDeviceConfigProperty(@NonNull String key, int defaultValue) {
+ final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL, key);
+ if (value == null) return defaultValue;
+
+ try {
+ return Integer.parseInt(value);
+ } catch (Exception e) {
+ Log.w(TAG, "error parsing value (" + value + ") of property " + key + ": " + e);
+ return defaultValue;
+ }
+ }
+
private interface ViewNodeFilter {
boolean matches(ViewNode node);
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 88228fb3ec16..a38c3cf9975e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -31,7 +31,6 @@ import android.os.SystemClock;
import android.service.autofill.augmented.AugmentedAutofillService;
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
-import android.text.format.DateUtils;
import android.util.Pair;
import android.util.Slog;
import android.view.autofill.AutofillId;
@@ -48,13 +47,17 @@ final class RemoteAugmentedAutofillService
private static final String TAG = RemoteAugmentedAutofillService.class.getSimpleName();
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+ private final int mIdleUnbindTimeoutMs;
+ private final int mRequestTimeoutMs;
RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
- boolean bindInstantServiceAllowed, boolean verbose) {
+ boolean bindInstantServiceAllowed, boolean verbose, int idleUnbindTimeoutMs,
+ int requestTimeoutMs) {
super(context, AugmentedAutofillService.SERVICE_INTERFACE, serviceName, userId, callbacks,
bindInstantServiceAllowed, verbose);
+ mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
+ mRequestTimeoutMs = requestTimeoutMs;
// Bind right away.
scheduleBind();
@@ -108,12 +111,12 @@ final class RemoteAugmentedAutofillService
@Override // from AbstractRemoteService
protected long getTimeoutIdleBindMillis() {
- return PERMANENT_BOUND_TIMEOUT_MS;
+ return mIdleUnbindTimeoutMs;
}
@Override // from AbstractRemoteService
protected long getRemoteRequestMillis() {
- return TIMEOUT_REMOTE_REQUEST_MILLIS;
+ return mRequestTimeoutMs;
}
/**
@@ -209,7 +212,7 @@ final class RemoteAugmentedAutofillService
protected void onTimeout(RemoteAugmentedAutofillService remoteService) {
// TODO(b/122858578): must update the logged AUTOFILL_AUGMENTED_REQUEST with the
// timeout
- Slog.w(TAG, "PendingAutofillRequest timed out (" + TIMEOUT_REMOTE_REQUEST_MILLIS
+ Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
+ "ms) for " + remoteService);
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
finish();
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index a8fd59add367..9f7a940c1d16 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -104,12 +104,12 @@ public final class ContentCaptureManagerService extends
private boolean mDisabledByDeviceConfig;
// Device-config settings that are cached and passed back to apps
- int mDevCfgLoggingLevel;
- int mDevCfgMaxBufferSize;
- int mDevCfgIdleFlushingFrequencyMs;
- int mDevCfgTextChangeFlushingFrequencyMs;
- int mDevCfgLogHistorySize;
- int mDevCfgIdleUnbindTimeoutMs;
+ @GuardedBy("mLock") int mDevCfgLoggingLevel;
+ @GuardedBy("mLock") int mDevCfgMaxBufferSize;
+ @GuardedBy("mLock") int mDevCfgIdleFlushingFrequencyMs;
+ @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs;
+ @GuardedBy("mLock") int mDevCfgLogHistorySize;
+ @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
@@ -249,26 +249,29 @@ public final class ContentCaptureManagerService extends
}
private void setFineTuneParamsFromDeviceConfig() {
- mDevCfgMaxBufferSize = ContentCaptureHelper.getIntDeviceConfigProperty(
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
- ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
- mDevCfgIdleFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
- ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
- mDevCfgTextChangeFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
- ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
- mDevCfgLogHistorySize = ContentCaptureHelper.getIntDeviceConfigProperty(
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
- mDevCfgIdleUnbindTimeoutMs = ContentCaptureHelper.getIntDeviceConfigProperty(
- ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
- (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
- if (verbose) {
- Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): bufferSize=" + mDevCfgMaxBufferSize
- + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
- + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
- + ", logHistory=" + mDevCfgLogHistorySize
- + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
+ synchronized (mLock) {
+ mDevCfgMaxBufferSize = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
+ ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
+ mDevCfgIdleFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
+ ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
+ mDevCfgTextChangeFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
+ ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
+ mDevCfgLogHistorySize = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
+ mDevCfgIdleUnbindTimeoutMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+ ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT,
+ (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS);
+ if (verbose) {
+ Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): "
+ + "bufferSize=" + mDevCfgMaxBufferSize
+ + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
+ + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
+ + ", logHistory=" + mDevCfgLogHistorySize
+ + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs);
+ }
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a5eab8550e71..ada3947477de 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -347,12 +347,6 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mPackagesLock")
private final SparseArray<ArraySet<String>> mPackages = new SparseArray<>();
- /**
- * List of volumes visible to any user.
- * TODO: may be have a map of userId -> volumes?
- */
- private final CopyOnWriteArrayList<VolumeInfo> mVisibleVols = new CopyOnWriteArrayList<>();
-
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
/** Holding lock for AppFuse business */
@@ -956,8 +950,6 @@ class StorageManagerService extends IStorageManager.Stub
addInternalVolumeLocked();
}
- mVisibleVols.clear();
-
try {
mVold.reset();
@@ -1895,9 +1887,6 @@ class StorageManagerService extends IStorageManager.Stub
private void mount(VolumeInfo vol) {
try {
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId);
- if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) {
- mVisibleVols.add(vol);
- }
} catch (Exception e) {
Slog.wtf(TAG, e);
}
@@ -1914,9 +1903,6 @@ class StorageManagerService extends IStorageManager.Stub
private void unmount(VolumeInfo vol) {
try {
mVold.unmount(vol.id);
- if ((vol.mountFlags & VolumeInfo.MOUNT_FLAG_VISIBLE) != 0) {
- mVisibleVols.remove(vol);
- }
} catch (Exception e) {
Slog.wtf(TAG, e);
}
@@ -3851,14 +3837,6 @@ class StorageManagerService extends IStorageManager.Stub
pw.decreaseIndent();
pw.println();
- pw.println("mVisibleVols:");
- pw.increaseIndent();
- for (int i = 0; i < mVisibleVols.size(); i++) {
- mVisibleVols.get(i).dump(pw);
- }
- pw.decreaseIndent();
-
- pw.println();
pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
pw.println();
@@ -4056,38 +4034,9 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public String[] getVisibleVolumesForUser(int userId) {
- synchronized (mLock) {
- if (!ArrayUtils.contains(mSystemUnlockedUsers, userId)) {
- return EmptyArray.STRING;
- }
- }
- final ArrayList<String> visibleVolsForUser = new ArrayList<>();
- for (int i = mVisibleVols.size() - 1; i >= 0; --i) {
- final VolumeInfo vol = mVisibleVols.get(i);
- if (vol.isVisibleForUser(userId)) {
- visibleVolsForUser.add(getVolumeLabel(vol));
- }
- }
- return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]);
- }
-
- @Override
public String getSandboxId(String packageName) {
return StorageManagerService.this.getSandboxId(packageName,
mPmInternal.getSharedUserIdForPackage(packageName));
}
-
- private String getVolumeLabel(VolumeInfo vol) {
- // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold
- switch (vol.getType()) {
- case VolumeInfo.TYPE_EMULATED:
- return "emulated";
- case VolumeInfo.TYPE_PUBLIC:
- return vol.fsUuid == null ? vol.id : vol.fsUuid;
- default:
- return null;
- }
- }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fd946cdfa48a..5633082ce4b3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -177,8 +177,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private ServiceState[] mServiceState;
- private int[] mNetworkType;
-
private int[] mVoiceActivationState;
private int[] mDataActivationState;
@@ -213,6 +211,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private CallAttributes mCallAttributes = new CallAttributes(new PreciseCallState(),
TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ // network type of the call associated with the mCallAttributes and mCallQuality
+ private int mCallNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+
private int[] mSrvccState;
private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -375,7 +376,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataConnectionNetworkType = new int[numPhones];
mCallIncomingNumber = new String[numPhones];
mServiceState = new ServiceState[numPhones];
- mNetworkType = new int[numPhones];
mVoiceActivationState = new int[numPhones];
mDataActivationState = new int[numPhones];
mUserMobileDataState = new boolean[numPhones];
@@ -396,7 +396,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
mCallIncomingNumber[i] = "";
mServiceState[i] = new ServiceState();
- mNetworkType[i] = mServiceState[i].getVoiceNetworkType();
mSignalStrength[i] = new SignalStrength();
mUserMobileDataState[i] = false;
mMessageWaiting[i] = false;
@@ -998,21 +997,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId)) {
mServiceState[phoneId] = state;
- boolean notifyCallAttributes = true;
- if (mNetworkType[phoneId] != mServiceState[phoneId].getVoiceNetworkType()) {
- mNetworkType[phoneId] = state.getVoiceNetworkType();
- mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
- mCallQuality);
- } else {
- // No change to network type, so no need to notify call attributes
- notifyCallAttributes = false;
- }
-
- if (mCallQuality == null) {
- // No call quality reported yet, so no need to notify call attributes
- notifyCallAttributes = false;
- }
-
for (Record r : mRecords) {
if (VDBG) {
log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
@@ -1040,14 +1024,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mRemoveList.add(r.binder);
}
}
- if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)) {
- try {
- r.callback.onCallAttributesChanged(mCallAttributes);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
}
} else {
log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
@@ -1574,7 +1550,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log("notifyPreciseCallState: mCallQuality is null, skipping call attributes");
notifyCallAttributes = false;
} else {
- mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
+ mCallAttributes = new CallAttributes(mPreciseCallState, mCallNetworkType,
mCallQuality);
}
@@ -1840,16 +1816,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void notifyCallQualityChanged(CallQuality callQuality, int phoneId) {
+ public void notifyCallQualityChanged(CallQuality callQuality, int phoneId,
+ int callNetworkType) {
if (!checkNotifyPermission("notifyCallQualityChanged()")) {
return;
}
// merge CallQuality with PreciseCallState and network type
mCallQuality = callQuality;
- mCallAttributes = new CallAttributes(mPreciseCallState,
- mNetworkType[phoneId],
- callQuality);
+ mCallNetworkType = callNetworkType;
+ mCallAttributes = new CallAttributes(mPreciseCallState, callNetworkType, callQuality);
synchronized (mRecords) {
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
@@ -1886,7 +1862,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mCallState=" + mCallState[i]);
pw.println("mCallIncomingNumber=" + mCallIncomingNumber[i]);
pw.println("mServiceState=" + mServiceState[i]);
- pw.println("mNetworkType=" + mNetworkType[i]);
pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
pw.println("mDataActivationState= " + mDataActivationState[i]);
pw.println("mUserMobileDataState= " + mUserMobileDataState[i]);
@@ -1900,6 +1875,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i).toString());
pw.decreaseIndent();
}
+ pw.println("mCallNetworkType=" + mCallNetworkType);
pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
pw.println("mPreciseCallState=" + mPreciseCallState);
pw.println("mCallDisconnectCause=" + mCallDisconnectCause);
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index d025d739055b..de41152570d8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -402,7 +402,7 @@ final class ActivityManagerConstants extends ContentObserver {
private void updateActivityStartsLoggingEnabled() {
mFlagActivityStartsLoggingEnabled = Settings.Global.getInt(mResolver,
- Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 0) == 1;
+ Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
}
private void updateBackgroundActivityStartsEnabled() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8f45df133663..f2902b172502 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1861,7 +1861,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessRecord proc;
int procState;
int statType;
- int pid;
+ int pid = -1;
long lastPssTime;
synchronized (ActivityManagerService.this) {
if (mPendingPssProcesses.size() <= 0) {
@@ -15039,7 +15039,7 @@ public class ActivityManagerService extends IActivityManager.Stub
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
- false, false, oldRecord.userId, oldRecord);
+ false, false, oldRecord.userId);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ queue.mQueueName + "] sending broadcast result of "
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 820caf12ac84..be17b1bc600c 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -38,6 +38,8 @@ public class BroadcastConstants {
static final String KEY_DEFERRAL = "bcast_deferral";
static final String KEY_DEFERRAL_DECAY_FACTOR = "bcast_deferral_decay_factor";
static final String KEY_DEFERRAL_FLOOR = "bcast_deferral_floor";
+ static final String KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT =
+ "bcast_allow_bg_activity_start_timeout";
// All time intervals are in milliseconds
private static final long DEFAULT_TIMEOUT = 10_000;
@@ -45,6 +47,7 @@ public class BroadcastConstants {
private static final long DEFAULT_DEFERRAL = 5_000;
private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
private static final long DEFAULT_DEFERRAL_FLOOR = 0;
+ private static final long DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT = 10_000;
// All time constants are in milliseconds
@@ -59,6 +62,8 @@ public class BroadcastConstants {
public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR;
// Minimum that the deferral time can decay to until the backlog fully clears
public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR;
+ // For how long after a whitelisted receiver's start its process can start a background activity
+ public long ALLOW_BG_ACTIVITY_START_TIMEOUT = DEFAULT_ALLOW_BG_ACTIVITY_START_TIMEOUT;
// Settings override tracking for this instance
private String mSettingsKey;
@@ -113,6 +118,8 @@ public class BroadcastConstants {
DEFERRAL_DECAY_FACTOR = mParser.getFloat(KEY_DEFERRAL_DECAY_FACTOR,
DEFERRAL_DECAY_FACTOR);
DEFERRAL_FLOOR = mParser.getLong(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR);
+ ALLOW_BG_ACTIVITY_START_TIMEOUT = mParser.getLong(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT,
+ ALLOW_BG_ACTIVITY_START_TIMEOUT);
}
}
@@ -145,6 +152,9 @@ public class BroadcastConstants {
pw.print(" "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = ");
TimeUtils.formatDuration(DEFERRAL_FLOOR, pw);
+
+ pw.print(" "); pw.print(KEY_ALLOW_BG_ACTIVITY_START_TIMEOUT); pw.print(" = ");
+ TimeUtils.formatDuration(ALLOW_BG_ACTIVITY_START_TIMEOUT, pw);
pw.println();
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index d9ea1da79f56..efb1c445925f 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -74,9 +74,6 @@ public final class BroadcastQueue {
static final int MAX_BROADCAST_SUMMARY_HISTORY
= ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
- // For how long after a whitelisted receiver's start its process can start a background activity
- private static final int RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS = 10_000;
-
final ActivityManagerService mService;
/**
@@ -310,9 +307,6 @@ public final class BroadcastQueue {
r.curApp = app;
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
- if (r.allowBackgroundActivityStarts) {
- app.addAllowBackgroundActivityStartsToken(r);
- }
mService.mProcessList.updateLruProcessLocked(app, false, null);
if (!skipOomAdj) {
mService.updateOomAdjLocked();
@@ -454,8 +448,25 @@ public final class BroadcastQueue {
Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
if (r.allowBackgroundActivityStarts && r.curApp != null) {
- r.curApp.removeAllowBackgroundActivityStartsToken(r);
- }
+ if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) {
+ // if the receiver has run for more than allowed bg activity start timeout,
+ // just remove the token for this process now and we're done
+ r.curApp.removeAllowBackgroundActivityStartsToken(r);
+ } else {
+ // the receiver had run for less than allowed bg activity start timeout,
+ // so allow the process to still start activities from bg for some more time
+ String msgToken = (r.curApp.toShortString() + r.toString()).intern();
+ // first, if there exists a past scheduled request to remove this token, drop
+ // that request - we don't want the token to be swept from under our feet...
+ mHandler.removeCallbacksAndMessages(msgToken);
+ // ...then schedule the removal of the token after the extended timeout
+ mHandler.postAtTime(() -> {
+ if (r.curApp != null) {
+ r.curApp.removeAllowBackgroundActivityStartsToken(r);
+ }
+ }, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
+ }
+ }
// If we're abandoning this broadcast before any receivers were actually spun up,
// nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
if (r.nextReceiver > 0) {
@@ -554,7 +565,7 @@ public final class BroadcastQueue {
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky, int sendingUser, BroadcastRecord br)
+ boolean ordered, boolean sticky, int sendingUser)
throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
@@ -562,15 +573,6 @@ public final class BroadcastQueue {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
- if (br.allowBackgroundActivityStarts) {
- app.addAllowBackgroundActivityStartsToken(br);
- // schedule removal of the whitelisting token after the timeout
- mHandler.postDelayed(() -> {
- if (app != null) {
- app.removeAllowBackgroundActivityStartsToken(br);
- }
- }, RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS);
- }
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
@@ -794,9 +796,13 @@ public final class BroadcastQueue {
skipReceiverLocked(r);
}
} else {
+ if (r.receiverTime == 0) {
+ r.receiverTime = SystemClock.uptimeMillis();
+ }
+ maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
- r.resultExtras, r.ordered, r.initialSticky, r.userId, r);
+ r.resultExtras, r.ordered, r.initialSticky, r.userId);
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
@@ -1100,7 +1106,7 @@ public final class BroadcastQueue {
}
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false, false, r.userId, r);
+ r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
@@ -1255,6 +1261,9 @@ public final class BroadcastQueue {
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
+ if (filter.receiverList != null) {
+ maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
+ }
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
@@ -1561,6 +1570,7 @@ public final class BroadcastQueue {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
+ maybeAddAllowBackgroundActivityStartsToken(app, r);
processCurBroadcastLocked(r, app, skipOomAdj);
return;
} catch (RemoteException e) {
@@ -1611,10 +1621,23 @@ public final class BroadcastQueue {
return;
}
+ maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
+ private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) {
+ if (r == null || proc == null || !r.allowBackgroundActivityStarts) {
+ return;
+ }
+ String msgToken = (proc.toShortString() + r.toString()).intern();
+ // first, if there exists a past scheduled request to remove this token, drop
+ // that request - we don't want the token to be swept from under our feet...
+ mHandler.removeCallbacksAndMessages(msgToken);
+ // ...then add the token
+ proc.addAllowBackgroundActivityStartsToken(r);
+ }
+
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (! mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3a61dd987cf5..30798a87a060 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1764,8 +1764,6 @@ public final class ProcessList {
.getPackagesForUid(uid);
final StorageManagerInternal storageManagerInternal =
LocalServices.getService(StorageManagerInternal.class);
- final String[] visibleVolIds = storageManagerInternal
- .getVisibleVolumesForUser(UserHandle.getUserId(uid));
final String sandboxId = storageManagerInternal.getSandboxId(app.info.packageName);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
@@ -1776,7 +1774,7 @@ public final class ProcessList {
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
- packageNames, visibleVolIds, sandboxId,
+ packageNames, sandboxId,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else if (hostingType.equals("app_zygote")) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
@@ -1785,14 +1783,14 @@ public final class ProcessList {
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
- packageNames, visibleVolIds, sandboxId, /*useBlastulaPool=*/ false,
+ packageNames, sandboxId, /*useBlastulaPool=*/ false,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
- packageNames, visibleVolIds, sandboxId,
+ packageNames, sandboxId,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index cbbbe4743108..894a704c5bba 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -38,8 +38,9 @@ import java.util.HashSet;
/**
* Maps system settings to system properties.
* <p>The properties are dynamically updated when settings change.
+ * @hide
*/
-class SettingsToPropertiesMapper {
+public class SettingsToPropertiesMapper {
private static final String TAG = "SettingsToPropertiesMapper";
@@ -156,8 +157,8 @@ class SettingsToPropertiesMapper {
* during current device booting.
* @return
*/
- public boolean isNativeFlagsResetPerformed() {
- String value = systemPropertiesGet(RESET_PERFORMED_PROPERTY);
+ public static boolean isNativeFlagsResetPerformed() {
+ String value = SystemProperties.get(RESET_PERFORMED_PROPERTY);
return "true".equals(value);
}
@@ -166,7 +167,7 @@ class SettingsToPropertiesMapper {
* booting.
* @return
*/
- public String[] getResetNativeCategories() {
+ public static String[] getResetNativeCategories() {
if (!isNativeFlagsResetPerformed()) {
return new String[0];
}
@@ -214,7 +215,7 @@ class SettingsToPropertiesMapper {
if (value == null) {
// It's impossible to remove system property, therefore we check previous value to
// avoid setting an empty string if the property wasn't set.
- if (TextUtils.isEmpty(systemPropertiesGet(key))) {
+ if (TextUtils.isEmpty(SystemProperties.get(key))) {
return;
}
value = "";
@@ -224,7 +225,7 @@ class SettingsToPropertiesMapper {
}
try {
- systemPropertiesSet(key, value);
+ SystemProperties.set(key, value);
} catch (Exception e) {
// Failure to set a property can be caused by SELinux denial. This usually indicates
// that the property wasn't whitelisted in sepolicy.
@@ -250,17 +251,7 @@ class SettingsToPropertiesMapper {
}
@VisibleForTesting
- protected String systemPropertiesGet(String key) {
- return SystemProperties.get(key);
- }
-
- @VisibleForTesting
- protected void systemPropertiesSet(String key, String value) {
- SystemProperties.set(key, value);
- }
-
- @VisibleForTesting
- protected String getResetFlagsFileContent() {
+ static String getResetFlagsFileContent() {
String content = null;
try {
File reset_flag_file = new File(RESET_RECORD_FILE_PATH);
@@ -279,4 +270,4 @@ class SettingsToPropertiesMapper {
String settingValue = Settings.Global.getString(mContentResolver, settingName);
setProperty(propName, settingValue);
}
-}
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ac20f6c7eaaf..1e406c01f255 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2214,7 +2214,11 @@ class UserController implements Handler.Callback {
void startUserWidgets(int userId) {
AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class);
if (awm != null) {
- awm.unlockUser(userId);
+ // Out of band, because this is called during a sequence with
+ // sensitive cross-service lock management
+ FgThread.getHandler().post(() -> {
+ awm.unlockUser(userId);
+ });
}
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 708de73f8eb2..4485a54b5cdf 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -144,7 +144,7 @@ final class HistoricalRegistry {
* Whether history is enabled.
*/
@GuardedBy("mInMemoryLock")
- private int mMode = AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE;
+ private int mMode = AppOpsManager.HISTORICAL_MODE_DISABLED;
/**
* This granularity has been chosen to allow clean delineation for intervals
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index afdfbe328ae2..5d802a76ae95 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -88,6 +88,7 @@ import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
@@ -274,6 +275,9 @@ public class AudioService extends IAudioService.Stub
private SettingsObserver mSettingsObserver;
+ /** @see AudioProductStrategies */
+ private static AudioProductStrategies sAudioProductStrategies;
+
private int mMode = AudioSystem.MODE_NORMAL;
// protects mRingerMode
private final Object mSettingsLock = new Object();
@@ -624,6 +628,8 @@ public class AudioService extends IAudioService.Stub
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
+ sAudioProductStrategies = new AudioProductStrategies();
+
// Initialize volume
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
if (maxCallVolume != -1) {
@@ -988,6 +994,14 @@ public class AudioService extends IAudioService.Stub
}
}
+ /**
+ * @return the {@link android.media.audiopolicy.AudioProductStrategies} discovered from the
+ * platform configuration file.
+ */
+ public @NonNull AudioProductStrategies getAudioProductStrategies() {
+ return sAudioProductStrategies;
+ }
+
private void checkAllAliasStreamVolumes() {
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
@@ -5787,7 +5801,7 @@ public class AudioService extends IAudioService.Stub
// - wired: logged before onSetWiredDeviceConnectionState() is executed
// - A2DP: logged at reception of method call
/*package*/ static final AudioEventLogger sDeviceLogger = new AudioEventLogger(
- LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP/hearing aid device connection BLABLI");
+ LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP/hearing aid device connection");
static final AudioEventLogger sForceUseLogger = new AudioEventLogger(
LOG_NB_EVENTS_FORCE_USE,
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 489194726c5a..77df10bf536a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -65,7 +65,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
new LongSparseArray<LocalDisplayDevice>();
@SuppressWarnings("unused") // Becomes active at instantiation time.
- private HotplugDisplayEventReceiver mHotplugReceiver;
+ private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
@@ -77,7 +78,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public void registerLocked() {
super.registerLocked();
- mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
+ mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper());
for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
tryConnectDisplayLocked(physicalDisplayId);
@@ -727,8 +728,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
- public HotplugDisplayEventReceiver(Looper looper) {
+ private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver {
+ PhysicalDisplayEventReceiver(Looper looper) {
super(looper, VSYNC_SOURCE_APP);
}
@@ -742,5 +743,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
}
+
+ @Override
+ public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onConfigChanged("
+ + "timestampNanos=" + timestampNanos
+ + ", builtInDisplayId=" + physicalDisplayId
+ + ", configId=" + configId + ")");
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index bffa8f486db7..3052e3cdcd21 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.input.InputManagerInternal;
import android.os.Binder;
import android.os.Build;
@@ -46,7 +47,6 @@ import android.service.dreams.IDreamManager;
import android.util.Slog;
import android.view.Display;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 6a4ccf2f5327..2026957b6c44 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -31,6 +31,8 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.tv.TvContract;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager.TvInputCallback;
import android.os.SystemProperties;
import android.provider.Settings.Global;
import android.util.Slog;
@@ -84,10 +86,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");
// Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
- // accept input switching request from HDMI devices. Requests for which the corresponding
- // input ID is not yet registered by TV input framework need to be buffered for delayed
- // processing.
- private final HashMap<Integer, String> mTvInputs = new HashMap<>();
+ // accept input switching request from HDMI devices.
+ @GuardedBy("mLock")
+ private final HashMap<Integer, String> mPortIdToTvInputs = new HashMap<>();
+
+ // A map from TV input id to HDMI device info.
+ @GuardedBy("mLock")
+ private final HashMap<String, HdmiDeviceInfo> mTvInputsToDeviceInfo = new HashMap<>();
// Copy of mDeviceInfos to guarantee thread-safety.
@GuardedBy("mLock")
@@ -103,14 +108,57 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
mSystemAudioControlFeatureEnabled =
mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
- // TODO(amyjojo): Maintain a portId to TvinputId map.
- mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
- mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
- mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
}
private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
+ private final TvInputCallback mTvInputCallback = new TvInputCallback() {
+ @Override
+ public void onInputAdded(String inputId) {
+ addOrUpdateTvInput(inputId);
+ }
+
+ @Override
+ public void onInputRemoved(String inputId) {
+ removeTvInput(inputId);
+ }
+
+ @Override
+ public void onInputUpdated(String inputId) {
+ addOrUpdateTvInput(inputId);
+ }
+ };
+
+ @ServiceThreadOnly
+ private void addOrUpdateTvInput(String inputId) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ TvInputInfo tvInfo = mService.getTvInputManager().getTvInputInfo(inputId);
+ if (tvInfo == null) {
+ return;
+ }
+ HdmiDeviceInfo info = tvInfo.getHdmiDeviceInfo();
+ if (info == null) {
+ return;
+ }
+ mPortIdToTvInputs.put(info.getPortId(), inputId);
+ mTvInputsToDeviceInfo.put(inputId, info);
+ }
+ }
+
+ @ServiceThreadOnly
+ private void removeTvInput(String inputId) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ if (mTvInputsToDeviceInfo.get(inputId) == null) {
+ return;
+ }
+ int portId = mTvInputsToDeviceInfo.get(inputId).getPortId();
+ mPortIdToTvInputs.remove(portId);
+ mTvInputsToDeviceInfo.remove(inputId);
+ }
+ }
+
/**
* Called when a device is newly added or a new device is detected or
* an existing device is updated.
@@ -248,13 +296,29 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
- } else if (!connected){
- // TODO(amyjojo): remove device from mDeviceInfo
+ } else if (!connected && mPortIdToTvInputs.get(portId) != null) {
+ String tvInputId = mPortIdToTvInputs.get(portId);
+ HdmiDeviceInfo info = mTvInputsToDeviceInfo.get(tvInputId);
+ if (info == null) {
+ return;
+ }
+ // Update with TIF on the device removal. TIF callback will update
+ // mPortIdToTvInputs and mPortIdToTvInputs.
+ removeCecDevice(info.getLogicalAddress());
}
}
@Override
@ServiceThreadOnly
+ protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
+ super.disableDevice(initiatedByCec, callback);
+ assertRunOnServiceThread();
+ mService.unregisterTvInputCallback(mTvInputCallback);
+ // TODO(amyjojo): check disableDevice and onStandby behaviors per spec
+ }
+
+ @Override
+ @ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
assertRunOnServiceThread();
mTvSystemAudioModeSupport = false;
@@ -280,6 +344,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mAddress, mService.getPhysicalAddress(), mDeviceType));
mService.sendCecCommand(
HdmiCecMessageBuilder.buildDeviceVendorIdCommand(mAddress, mService.getVendorId()));
+ mService.registerTvInputCallback(mTvInputCallback);
int systemAudioControlOnPowerOnProp =
SystemProperties.getInt(
PROPERTY_SYSTEM_AUDIO_CONTROL_ON_POWER_ON,
@@ -1071,9 +1136,9 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
setLocalActivePort(portId);
return;
} else {
- String uri = mTvInputs.get(portId);
+ String uri = mPortIdToTvInputs.get(portId);
if (uri != null) {
- switchToTvInput(mTvInputs.get(portId));
+ switchToTvInput(uri);
} else {
HdmiLogger.debug("Port number does not match any Tv Input.");
return;
@@ -1222,7 +1287,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
pw.println("mArcIntentUsed: " + mArcIntentUsed);
pw.println("mRoutingPort: " + getRoutingPort());
pw.println("mLocalActivePort: " + getLocalActivePort());
- HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+ HdmiUtils.dumpMap(pw, "mPortIdToTvInputs:", mPortIdToTvInputs);
+ HdmiUtils.dumpMap(pw, "mTvInputsToDeviceInfo:", mTvInputsToDeviceInfo);
HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
pw.decreaseIndent();
super.dump(pw);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 072238ee7f55..f5adb0111559 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -576,7 +576,8 @@ public class HdmiControlService extends SystemService {
Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Global.MHL_INPUT_SWITCHING_ENABLED,
Global.MHL_POWER_CHARGE_ENABLED,
- Global.HDMI_CEC_SWITCH_ENABLED
+ Global.HDMI_CEC_SWITCH_ENABLED,
+ Global.DEVICE_NAME
};
for (String s : settings) {
resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -642,6 +643,10 @@ public class HdmiControlService extends SystemService {
case Global.MHL_POWER_CHARGE_ENABLED:
mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled));
break;
+ case Global.DEVICE_NAME:
+ String deviceName = readStringSetting(option, Build.MODEL);
+ setDisplayName(deviceName);
+ break;
}
}
}
@@ -670,6 +675,15 @@ public class HdmiControlService extends SystemService {
return SystemProperties.getBoolean(key, defVal);
}
+ String readStringSetting(String key, String defVal) {
+ ContentResolver cr = getContext().getContentResolver();
+ String content = Global.getString(cr, key);
+ if (TextUtils.isEmpty(content)) {
+ return defVal;
+ }
+ return content;
+ }
+
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -1178,13 +1192,29 @@ public class HdmiControlService extends SystemService {
}
private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) {
- // TODO: find better name instead of model name.
- String displayName = Build.MODEL;
+ String displayName = readStringSetting(Global.DEVICE_NAME, Build.MODEL);
return new HdmiDeviceInfo(logicalAddress,
getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
getVendorId(), displayName, powerStatus);
}
+ // Set the display name in HdmiDeviceInfo of the current devices to content provided by
+ // Global.DEVICE_NAME. Only set and broadcast if the new name is different.
+ private void setDisplayName(String newDisplayName) {
+ for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+ HdmiDeviceInfo deviceInfo = device.getDeviceInfo();
+ if (deviceInfo.getDisplayName().equals(newDisplayName)) {
+ continue;
+ }
+ device.setDeviceInfo(new HdmiDeviceInfo(
+ deviceInfo.getLogicalAddress(), deviceInfo.getPhysicalAddress(),
+ deviceInfo.getPortId(), deviceInfo.getDeviceType(), deviceInfo.getVendorId(),
+ newDisplayName, deviceInfo.getDevicePowerStatus()));
+ sendCecCommand(HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ device.mAddress, Constants.ADDR_TV, newDisplayName));
+ }
+ }
+
@ServiceThreadOnly
void handleMhlHotplugEvent(int portId, boolean connected) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index c2ae53f69309..51187dff4d59 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -81,20 +81,16 @@ public final class StorageController extends StateController {
synchronized (mLock) {
for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
final JobStatus ts = mTrackedTasks.valueAt(i);
- boolean previous = ts.setStorageNotLowConstraintSatisfied(storageNotLow);
- if (previous != storageNotLow) {
- reportChange = true;
- }
+ reportChange |= ts.setStorageNotLowConstraintSatisfied(storageNotLow);
}
}
- // Let the scheduler know that state has changed. This may or may not result in an
- // execution.
- if (reportChange) {
- mStateChangedListener.onControllerStateChanged();
- }
- // Also tell the scheduler that any ready jobs should be flushed.
if (storageNotLow) {
+ // Tell the scheduler that any ready jobs should be flushed.
mStateChangedListener.onRunJobNow(null);
+ } else if (reportChange) {
+ // Let the scheduler know that state has changed. This may or may not result in an
+ // execution.
+ mStateChangedListener.onControllerStateChanged();
}
}
@@ -143,9 +139,10 @@ public final class StorageController extends StateController {
+ sElapsedRealtimeClock.millis());
}
mStorageLow = true;
+ maybeReportNewStorageState();
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (DEBUG) {
- Slog.d(TAG, "Available stoage high enough to do work. @ "
+ Slog.d(TAG, "Available storage high enough to do work. @ "
+ sElapsedRealtimeClock.millis());
}
mStorageLow = false;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 28fdd95afb6a..51563008464c 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -140,6 +140,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
+ // these need to match ElapsedRealtimeFlags enum in types.hal
+ private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1;
+
// IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
private static final int GPS_DELETE_EPHEMERIS = 0x0001;
private static final int GPS_DELETE_ALMANAC = 0x0002;
@@ -757,10 +760,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
long timestamp = location.getTime();
- native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
- verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
- timestamp);
+
+ int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS;
+ long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
+
+ native_inject_best_location(
+ gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos);
}
/** Returns true if the location request is too frequent. */
@@ -1260,9 +1269,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
- // It would be nice to push the elapsed real-time timestamp
- // further down the stack, but this is still useful
- location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
location.setExtras(mLocationExtras.getBundle());
reportLocation(location);
@@ -2151,17 +2157,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private native int native_read_nmea(byte[] buffer, int bufferSize);
private native void native_inject_best_location(
- int gnssLocationFlags,
- double latitudeDegrees,
- double longitudeDegrees,
- double altitudeMeters,
- float speedMetersPerSec,
- float bearingDegrees,
- float horizontalAccuracyMeters,
- float verticalAccuracyMeters,
- float speedAccuracyMetersPerSecond,
- float bearingAccuracyDegrees,
- long timestamp);
+ int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
+ double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
+ float horizontalAccuracyMeters, float verticalAccuracyMeters,
+ float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
+ long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos);
private native void native_inject_location(double latitude, double longitude, float accuracy);
@@ -2188,4 +2188,4 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
int lac, int cid);
private native void native_agps_set_id(int type, String setid);
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index afe34737fdee..00e1ffa7450d 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -34,13 +34,11 @@ import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-import com.android.internal.os.TransferPipe;
import com.android.server.FgThread;
import com.android.server.LocationManagerService;
import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -189,14 +187,6 @@ public class LocationProviderProxy extends AbstractLocationProvider {
pw.println(" additional packages=" + mProviderPackages);
}
}
- mServiceWatcher.runOnBinderBlocking(binder -> {
- try {
- TransferPipe.dumpAsync(binder, fd, args);
- } catch (IOException | RemoteException e) {
- pw.println(" <failed to dump location provider: " + e + ">");
- }
- return null;
- }, null);
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index aa85c835a5fd..ee968c87e753 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -123,7 +123,6 @@ import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
@@ -277,7 +276,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* @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, String managedUserPassword) {
+ public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
// Only for managed profile
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
@@ -312,7 +311,12 @@ public class LockSettingsService extends ILockSettings.Stub {
byte[] randomLockSeed = new byte[] {};
try {
randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
- String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
+ 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, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
managedUserPassword, quality, managedUserId);
@@ -321,6 +325,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// 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 | RemoteException 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
@@ -618,7 +623,7 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
final long handle = getSyntheticPasswordHandleLocked(userId);
- final String noCredential = null;
+ final byte[] noCredential = null;
AuthenticationResult result =
mSpManager.unwrapPasswordBasedSyntheticPassword(
getGateKeeperService(), handle, noCredential, userId, null);
@@ -956,7 +961,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
- String managedUserPassword) {
+ byte[] managedUserPassword) {
checkWritePermission(userId);
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -969,8 +974,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@GuardedBy("mSeparateChallengeLock")
- private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
- String managedUserPassword) {
+ private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
+ boolean enabled, byte[] managedUserPassword) {
final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
try {
@@ -1113,24 +1118,28 @@ public class LockSettingsService extends ILockSettings.Stub {
return mStorage.hasCredential(userId);
}
- private void setKeystorePassword(String password, int userHandle) {
+ private void setKeystorePassword(byte[] password, int userHandle) {
final KeyStore ks = KeyStore.getInstance();
- ks.onUserPasswordChanged(userHandle, password);
+ // TODO(b/120484642): Update keystore to accept byte[] passwords
+ String passwordString = password == null ? null : new String(password);
+ ks.onUserPasswordChanged(userHandle, passwordString);
}
- private void unlockKeystore(String password, int userHandle) {
+ private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+ // TODO(b/120484642): Update keystore to accept byte[] passwords
+ String passwordString = password == null ? null : new String(password);
final KeyStore ks = KeyStore.getInstance();
- ks.unlock(userHandle, password);
+ ks.unlock(userHandle, passwordString);
}
@VisibleForTesting
- protected String getDecryptedPasswordForTiedProfile(int userId)
+ protected byte[] getDecryptedPasswordForTiedProfile(int userId)
throws KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
CertificateException, IOException {
- if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
+ if (DEBUG) Slog.v(TAG, "Get child profile decrypted key");
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
throw new FileNotFoundException("Child profile lock file not found");
@@ -1149,7 +1158,7 @@ public class LockSettingsService extends ILockSettings.Stub {
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
decryptionResult = cipher.doFinal(encryptedPassword);
- return new String(decryptionResult, StandardCharsets.UTF_8);
+ return decryptionResult;
}
private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
@@ -1226,11 +1235,11 @@ public class LockSettingsService extends ILockSettings.Stub {
&& mUserManager.isUserRunning(userInfo.id);
}
- private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
+ private Map<Integer, byte[]> getDecryptedPasswordsForAllTiedProfiles(int userId) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return null;
}
- Map<Integer, String> result = new ArrayMap<Integer, String>();
+ Map<Integer, byte[]> result = new ArrayMap<Integer, byte[]>();
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
final int size = profiles.size();
for (int i = 0; i < size; i++) {
@@ -1268,7 +1277,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* terminates when the user is a managed profile.
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
- Map<Integer, String> profilePasswordMap) throws RemoteException {
+ Map<Integer, byte[]> profilePasswordMap) throws RemoteException {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return;
}
@@ -1317,9 +1326,10 @@ 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 void setLockCredential(String credential, int type, String savedCredential,
- int requestedQuality, int userId)
+ public void setLockCredential(byte[] credential, int type,
+ byte[] savedCredential, int requestedQuality, int userId)
throws RemoteException {
+
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
@@ -1333,14 +1343,14 @@ public class LockSettingsService extends ILockSettings.Stub {
notifySeparateProfileChallengeChanged(userId);
}
- private void setLockCredentialInternal(String credential, int credentialType,
- String savedCredential, int requestedQuality, int userId) throws RemoteException {
+ private void setLockCredentialInternal(byte[] credential, int credentialType,
+ byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
// Normalize savedCredential and credential such that empty string is always represented
// as null.
- if (TextUtils.isEmpty(savedCredential)) {
+ if (savedCredential == null || savedCredential.length == 0) {
savedCredential = null;
}
- if (TextUtils.isEmpty(credential)) {
+ if (credential == null || credential.length == 0) {
credential = null;
}
synchronized (mSpManager) {
@@ -1409,7 +1419,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mStorage.writeCredentialHash(willStore, userId);
// push new secret and auth token to vold
GateKeeperResponse gkResponse = getGateKeeperService()
- .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
+ .verifyChallenge(userId, 0, willStore.hash, credential);
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
fixateNewestUserKeyAuth(userId);
// Refresh the auth token
@@ -1429,9 +1439,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@VisibleForTesting
- protected void tieProfileLockToParent(int userId, String password) {
+ protected void tieProfileLockToParent(int userId, byte[] password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
- byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
byte[] encryptionResult;
byte[] iv;
try {
@@ -1465,7 +1474,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(randomLockSeed);
+ encryptionResult = cipher.doFinal(password);
iv = cipher.getIV();
} finally {
// The original key can now be discarded.
@@ -1490,17 +1499,11 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private byte[] enrollCredential(byte[] enrolledHandle,
- String enrolledCredential, String toEnroll, int userId)
+ byte[] enrolledCredential, byte[] toEnroll, int userId)
throws RemoteException {
checkWritePermission(userId);
- byte[] enrolledCredentialBytes = enrolledCredential == null
- ? null
- : enrolledCredential.getBytes();
- byte[] toEnrollBytes = toEnroll == null
- ? null
- : toEnroll.getBytes();
GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
- enrolledCredentialBytes, toEnrollBytes);
+ enrolledCredential, toEnroll);
if (response == null) {
return null;
@@ -1521,7 +1524,7 @@ public class LockSettingsService extends ILockSettings.Stub {
addUserKeyAuth(userId, null, key);
}
- private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
+ private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr)
throws RemoteException {
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
if (vcr == null) {
@@ -1543,16 +1546,15 @@ public class LockSettingsService extends ILockSettings.Stub {
addUserKeyAuth(userId, null, null);
}
- private static byte[] secretFromCredential(String credential) throws RemoteException {
+ private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
// Personalize the hash
- byte[] personalization = "Android FBE credential hash"
- .getBytes(StandardCharsets.UTF_8);
+ byte[] personalization = "Android FBE credential hash".getBytes();
// Pad it to the block size of the hash function
personalization = Arrays.copyOf(personalization, 128);
digest.update(personalization);
- digest.update(credential.getBytes(StandardCharsets.UTF_8));
+ digest.update(credential);
return digest.digest();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
@@ -1588,7 +1590,7 @@ public class LockSettingsService extends ILockSettings.Stub {
checkWritePermission(userId);
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
int managedUserId = -1;
- String managedUserDecryptedPassword = null;
+ byte[] managedUserDecryptedPassword = null;
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock managed profile with unified lock
@@ -1625,17 +1627,20 @@ public class LockSettingsService extends ILockSettings.Stub {
tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
}
}
+ if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) {
+ Arrays.fill(managedUserDecryptedPassword, (byte) 0);
+ }
}
@Override
- public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
+ public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
}
@Override
- public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
+ public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
int userId) throws RemoteException {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, true, challenge, userId,
@@ -1646,10 +1651,10 @@ 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(String credential, int credentialType,
+ private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
- if (TextUtils.isEmpty(credential)) {
+ if (credential == null || credential.length == 0) {
throw new IllegalArgumentException("Credential can't be null or empty");
}
if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
@@ -1684,9 +1689,9 @@ public class LockSettingsService extends ILockSettings.Stub {
boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
&& storedHash.isBaseZeroPattern;
- String credentialToVerify;
+ byte[] credentialToVerify;
if (shouldReEnrollBaseZero) {
- credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
+ credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
} else {
credentialToVerify = credential;
}
@@ -1706,7 +1711,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
+ public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type,
long challenge, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
if (!isManagedProfileWithUnifiedLock(userId)) {
@@ -1748,14 +1753,15 @@ public class LockSettingsService extends ILockSettings.Stub {
* hash to GK.
*/
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
- String credential, boolean hasChallenge, long challenge,
+ byte[] credential, boolean hasChallenge, long challenge,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
- if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
+ if ((storedHash == null || storedHash.hash.length == 0)
+ && (credential == null || credential.length == 0)) {
// don't need to pass empty credentials to GateKeeper
return VerifyCredentialResponse.OK;
}
- if (storedHash == null || TextUtils.isEmpty(credential)) {
+ if (storedHash == null || credential == null || credential.length == 0) {
return VerifyCredentialResponse.ERROR;
}
@@ -1766,14 +1772,14 @@ public class LockSettingsService extends ILockSettings.Stub {
if (storedHash.version == CredentialHash.VERSION_LEGACY) {
final byte[] hash;
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
- hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
+ hash = LockPatternUtils.patternToHash(
+ LockPatternUtils.byteArrayToPattern(credential));
} else {
- hash = mLockPatternUtils.legacyPasswordToHash(credential, userId)
- .getBytes(StandardCharsets.UTF_8);
+ hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
}
if (Arrays.equals(hash, storedHash.hash)) {
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
- unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
+ unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
} else {
unlockKeystore(credential, userId);
}
@@ -1804,7 +1810,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
GateKeeperResponse gateKeeperResponse = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
+ .verifyChallenge(userId, challenge, storedHash.hash, credential);
VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
@@ -1863,7 +1869,7 @@ public class LockSettingsService extends ILockSettings.Stub {
* Call this method to notify DPMS regarding the latest password metric. This should be called
* when the user is authenticating or when a new password is being set.
*/
- private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
+ private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) {
final PasswordMetrics metrics;
if (password == null) {
metrics = new PasswordMetrics();
@@ -1912,6 +1918,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
final IStorageManager service = mInjector.getStorageManager();
+ // TODO(b/120484642): Update vold to return a password as a byte array
String password;
long identity = Binder.clearCallingIdentity();
try {
@@ -1926,8 +1933,8 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
if (mLockPatternUtils.isLockPatternEnabled(userId)) {
- if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
- null /* progressCallback */)
+ if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ userId, null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
return true;
}
@@ -1937,8 +1944,8 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
- if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
- null /* progressCallback */)
+ if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ userId, null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
return true;
}
@@ -1966,7 +1973,8 @@ public class LockSettingsService extends ILockSettings.Stub {
} catch (RemoteException ex) {
Slog.w(TAG, "unable to clear GK secure user id");
}
- if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (unknownUser || userInfo == null || userInfo.isManagedProfile()) {
removeKeystoreProfileKey(userId);
}
}
@@ -2322,7 +2330,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@GuardedBy("mSpManager")
@VisibleForTesting
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
- String credential, int credentialType, int requestedQuality,
+ byte[] credential, int credentialType, int requestedQuality,
int userId) throws RemoteException {
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
@@ -2383,7 +2391,7 @@ public class LockSettingsService extends ILockSettings.Stub {
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
- private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
+ private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int
credentialType, boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
@@ -2482,12 +2490,12 @@ public class LockSettingsService extends ILockSettings.Stub {
* added back when new password is set in future.
*/
@GuardedBy("mSpManager")
- private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
+ private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType,
AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
credential, credentialType, auth, requestedQuality, userId);
- final Map<Integer, String> profilePasswords;
+ final Map<Integer, byte[]> profilePasswords;
if (credential != null) {
// // not needed by synchronizeUnifiedWorkChallengeForProfiles()
profilePasswords = null;
@@ -2526,12 +2534,19 @@ public class LockSettingsService extends ILockSettings.Stub {
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
notifyActivePasswordMetricsAvailable(credential, userId);
+
+ if (profilePasswords != null) {
+ for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
+ Arrays.fill(entry.getValue(), (byte) 0);
+ }
+ }
+
return newHandle;
}
@GuardedBy("mSpManager")
- private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
- String savedCredential, int requestedQuality, int userId) throws RemoteException {
+ private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
+ byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
if (isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
@@ -2604,9 +2619,9 @@ public class LockSettingsService extends ILockSettings.Stub {
* If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
- public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
+ public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- if (TextUtils.isEmpty(currentCredential)) {
+ if (currentCredential == null || currentCredential.length == 0) {
currentCredential = null;
}
if (isManagedProfileWithUnifiedLock(userId)) {
@@ -2700,7 +2715,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle,
byte[] token, int requestedQuality, int userId) throws RemoteException {
boolean result;
synchronized (mSpManager) {
@@ -2720,7 +2735,7 @@ public class LockSettingsService extends ILockSettings.Stub {
return result;
}
- private boolean setLockCredentialWithTokenInternal(String credential, int type,
+ private boolean setLockCredentialWithTokenInternal(byte[] credential, int type,
long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
final AuthenticationResult result;
synchronized (mSpManager) {
@@ -2947,8 +2962,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@Override
- public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
- byte[] token, int requestedQuality, int userId) {
+ public boolean setLockCredentialWithToken(byte[] credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 6163077e1acf..ee22264112ab 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -190,22 +190,30 @@ class LockSettingsShellCommand extends ShellCommand {
}
private void runSetPattern() {
- mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId);
getOutPrintWriter().println("Pattern set to '" + mNew + "'");
}
private void runSetPassword() {
- mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
+ byte[] newBytes = mNew != null ? mNew.getBytes() : null;
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC,
+ mCurrentUserId);
getOutPrintWriter().println("Password set to '" + mNew + "'");
}
private void runSetPin() {
- mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
+ byte[] newBytes = mNew != null ? mNew.getBytes() : null;
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC,
+ mCurrentUserId);
getOutPrintWriter().println("Pin set to '" + mNew + "'");
}
private void runClear() {
- mLockPatternUtils.clearLock(mOld, mCurrentUserId);
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.clearLock(oldBytes, mCurrentUserId);
getOutPrintWriter().println("Lock credential cleared");
}
@@ -232,7 +240,8 @@ class LockSettingsShellCommand extends ShellCommand {
try {
final boolean result;
if (havePassword) {
- result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
+ byte[] passwordBytes = mOld != null ? mOld.getBytes() : null;
+ result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId);
} else {
result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId);
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 0e195bcc98e0..ea39dff1acc9 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -97,7 +97,7 @@ public class SyntheticPasswordManager {
private static final String WEAVER_SLOT_NAME = "weaver";
public static final long DEFAULT_HANDLE = 0L;
- private static final String DEFAULT_PASSWORD = "default-password";
+ private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes();
private static final byte WEAVER_VERSION = 1;
private static final int INVALID_WEAVER_SLOT = -1;
@@ -165,7 +165,7 @@ public class SyntheticPasswordManager {
}
}
- public String deriveKeyStorePassword() {
+ public byte[] deriveKeyStorePassword() {
return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
}
@@ -454,11 +454,11 @@ public class SyntheticPasswordManager {
*
*/
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
- byte[] hash, String credential, int userId) throws RemoteException {
+ byte[] hash, byte[] credential, int userId) throws RemoteException {
AuthenticationToken result = AuthenticationToken.create();
GateKeeperResponse response;
if (hash != null) {
- response = gatekeeper.enroll(userId, hash, credential.getBytes(),
+ response = gatekeeper.enroll(userId, hash, credential,
result.deriveGkPassword());
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
@@ -616,7 +616,7 @@ public class SyntheticPasswordManager {
* @see #clearSidForUser
*/
public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- String credential, int credentialType, AuthenticationToken authToken,
+ byte[] credential, int credentialType, AuthenticationToken authToken,
int requestedQuality, int userId)
throws RemoteException {
if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
@@ -670,7 +670,7 @@ public class SyntheticPasswordManager {
}
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
- String userCredential, int credentialType,
+ byte[] userCredential, int credentialType,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
PersistentData persistentData = mStorage.readPersistentDataBlock();
if (persistentData.type == PersistentData.TYPE_SP) {
@@ -839,7 +839,7 @@ public class SyntheticPasswordManager {
* unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
*/
public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- long handle, String credential, int userId,
+ long handle, byte[] credential, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
if (credential == null) {
credential = DEFAULT_PASSWORD;
@@ -1152,7 +1152,7 @@ public class SyntheticPasswordManager {
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
}
- private byte[] computePasswordToken(String password, PasswordData data) {
+ private byte[] computePasswordToken(byte[] password, PasswordData data) {
return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
PASSWORD_TOKEN_LENGTH);
}
@@ -1173,8 +1173,8 @@ public class SyntheticPasswordManager {
return nativeSidFromPasswordHandle(handle);
}
- protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
- return new Scrypt().scrypt(password.getBytes(), salt, N, r, p, outLen);
+ protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
+ return new Scrypt().scrypt(password, salt, n, r, p, outLen);
}
native long nativeSidFromPasswordHandle(byte[] handle);
@@ -1195,17 +1195,17 @@ public class SyntheticPasswordManager {
return result;
}
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
- public static String bytesToHex(byte[] bytes) {
+ protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
+ private static byte[] bytesToHex(byte[] bytes) {
if (bytes == null) {
- return "null";
+ return "null".getBytes();
}
- char[] hexChars = new char[bytes.length * 2];
+ byte[] hexBytes = new byte[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
- hexChars[j * 2] = hexArray[v >>> 4];
- hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
+ hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
- return new String(hexChars);
+ return hexBytes;
}
}
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 e7a71b99a213..5676da213dd2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -38,7 +38,6 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnaps
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -51,6 +50,7 @@ import java.security.UnrecoverableKeyException;
import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -85,7 +85,7 @@ public class KeySyncTask implements Runnable {
private final RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private final int mUserId;
private final int mCredentialType;
- private final String mCredential;
+ private final byte[] mCredential;
private final boolean mCredentialUpdated;
private final PlatformKeyManager mPlatformKeyManager;
private final RecoverySnapshotStorage mRecoverySnapshotStorage;
@@ -100,7 +100,7 @@ public class KeySyncTask implements Runnable {
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
int userId,
int credentialType,
- String credential,
+ byte[] credential,
boolean credentialUpdated
) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException {
return new KeySyncTask(
@@ -134,7 +134,7 @@ public class KeySyncTask implements Runnable {
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
int userId,
int credentialType,
- String credential,
+ byte[] credential,
boolean credentialUpdated,
PlatformKeyManager platformKeyManager,
TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
@@ -450,7 +450,7 @@ public class KeySyncTask implements Runnable {
*/
@VisibleForTesting
@KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(
- int credentialType, String credential) {
+ int credentialType, byte[] credential) {
if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
return KeyChainProtectionParams.UI_FORMAT_PATTERN;
} else if (isPin(credential)) {
@@ -475,13 +475,13 @@ public class KeySyncTask implements Runnable {
* Returns {@code true} if {@code credential} looks like a pin.
*/
@VisibleForTesting
- static boolean isPin(@Nullable String credential) {
+ static boolean isPin(@Nullable byte[] credential) {
if (credential == null) {
return false;
}
- int length = credential.length();
+ int length = credential.length;
for (int i = 0; i < length; i++) {
- if (!Character.isDigit(credential.charAt(i))) {
+ if (!Character.isDigit((char) credential[i])) {
return false;
}
}
@@ -494,8 +494,7 @@ public class KeySyncTask implements Runnable {
* @return The SHA-256 hash.
*/
@VisibleForTesting
- static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) {
- byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
+ static byte[] hashCredentialsBySaltedSha256(byte[] salt, byte[] credentialsBytes) {
ByteBuffer byteBuffer = ByteBuffer.allocate(
salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -506,17 +505,19 @@ public class KeySyncTask implements Runnable {
byte[] bytes = byteBuffer.array();
try {
- return MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
+ byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
+ Arrays.fill(bytes, (byte) 0);
+ return hash;
} catch (NoSuchAlgorithmException e) {
// Impossible, SHA-256 must be supported on Android.
throw new RuntimeException(e);
}
}
- private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) {
+ private byte[] hashCredentialsByScrypt(byte[] salt, byte[] credentials) {
return mScrypt.scrypt(
- credentials.getBytes(StandardCharsets.UTF_8), salt,
- SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES);
+ credentials, salt, SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P,
+ SCRYPT_PARAM_OUTLEN_BYTES);
}
private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index ed864c0221c9..47b9c27284e5 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -892,13 +892,13 @@ public class RecoverableKeyStoreManager {
* This function can only be used inside LockSettingsService.
*
* @param storedHashType from {@code CredentialHash}
- * @param credential - unencrypted String. Password length should be at most 16 symbols {@code
- * mPasswordMaxLength}
+ * @param credential - unencrypted byte array. Password length should be at most 16 symbols
+ * {@code mPasswordMaxLength}
* @param userId for user who just unlocked the device.
* @hide
*/
public void lockScreenSecretAvailable(
- int storedHashType, @NonNull String credential, int userId) {
+ int storedHashType, @NonNull byte[] credential, int userId) {
// So as not to block the critical path unlocking the phone, defer to another thread.
try {
mExecutorService.execute(KeySyncTask.newInstance(
@@ -923,13 +923,13 @@ public class RecoverableKeyStoreManager {
* This function can only be used inside LockSettingsService.
*
* @param storedHashType from {@code CredentialHash}
- * @param credential - unencrypted String
+ * @param credential - unencrypted byte array
* @param userId for the user whose lock screen credentials were changed.
* @hide
*/
public void lockScreenSecretChanged(
int storedHashType,
- @Nullable String credential,
+ @Nullable byte[] credential,
int userId) {
// So as not to block the critical path unlocking the phone, defer to another thread.
try {
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 057429c3e7d4..90a36723de4d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -87,10 +87,30 @@ public class TestOnlyInsecureCertificateHelper {
|| isTestOnlyCertificateAlias(rootCertificateAlias);
}
- public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) {
- return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD)
- && (credential != null)
- && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
+ /**
+ * Checks whether a password is in "Insecure mode"
+ * @param credentialType the type of credential, e.g. pattern and password
+ * @param credential the pattern or password
+ * @return true, if the credential is in "Insecure mode"
+ */
+ public boolean doesCredentialSupportInsecureMode(int credentialType, byte[] credential) {
+ if (credential == null) {
+ return false;
+ }
+ if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ return false;
+ }
+ byte[] insecurePasswordPrefixBytes =
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes();
+ if (credential.length < insecurePasswordPrefixBytes.length) {
+ return false;
+ }
+ for (int i = 0; i < insecurePasswordPrefixBytes.length; i++) {
+ if (credential[i] != insecurePasswordPrefixBytes[i]) {
+ return false;
+ }
+ }
+ return true;
}
public Map<String, Pair<SecretKey, byte[]>> keepOnlyWhitelistedInsecureKeys(
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 4dd58e0b9969..a4c04b2e64aa 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -22,6 +22,10 @@ import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.apex.IApexService;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
@@ -49,17 +53,29 @@ import java.util.stream.Collectors;
class ApexManager {
static final String TAG = "ApexManager";
private final IApexService mApexService;
+ private final Context mContext;
private final Object mLock = new Object();
@GuardedBy("mLock")
private Map<String, PackageInfo> mActivePackagesCache;
- ApexManager() {
+ ApexManager(Context context) {
try {
mApexService = IApexService.Stub.asInterface(
ServiceManager.getServiceOrThrow("apexservice"));
} catch (ServiceNotFoundException e) {
throw new IllegalStateException("Required service apexservice not available");
}
+ mContext = context;
+ }
+
+ void systemReady() {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onBootCompleted();
+ mContext.unregisterReceiver(this);
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
private void populateActivePackagesCacheIfNeeded() {
@@ -207,6 +223,7 @@ class ApexManager {
* @return true if APEX packages can be managed on this device, false otherwise.
*/
boolean isApexSupported() {
+ populateActivePackagesCacheIfNeeded();
// There is no system-wide property available to check if APEX are flattened and hence can't
// be updated. In absence of such property, we assume that if we didn't index APEX packages
// since they were flattened, no APEX management should be possible.
@@ -270,6 +287,12 @@ class ApexManager {
ipw.println("State: ACTIVATED");
} else if (si.isActivationFailed) {
ipw.println("State: ACTIVATION FAILED");
+ } else if (si.isSuccess) {
+ ipw.println("State: SUCCESS");
+ } else if (si.isRollbackInProgress) {
+ ipw.println("State: ROLLBACK IN PROGRESS");
+ } else if (si.isRolledBack) {
+ ipw.println("State: ROLLED BACK");
}
ipw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index b52c02100faf..1c9028d10ca2 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -333,7 +333,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
- optimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
+ optimizer.performDexOpt(pkg,
null /* ISAs */,
null /* CompilerStats.PackageStats */,
mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5b3820815f92..580137db1630 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -125,7 +125,7 @@ public class PackageDexOptimizer {
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
* synchronized on {@link #mInstallLock}.
*/
- int performDexOpt(PackageParser.Package pkg, List<SharedLibraryInfo> sharedLibraries,
+ int performDexOpt(PackageParser.Package pkg,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
if (pkg.applicationInfo.uid == -1) {
@@ -138,7 +138,7 @@ public class PackageDexOptimizer {
synchronized (mInstallLock) {
final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
try {
- return performDexOptLI(pkg, sharedLibraries, instructionSets,
+ return performDexOptLI(pkg, instructionSets,
packageStats, packageUseInfo, options);
} finally {
releaseWakeLockLI(acquireTime);
@@ -152,9 +152,9 @@ public class PackageDexOptimizer {
*/
@GuardedBy("mInstallLock")
private int performDexOptLI(PackageParser.Package pkg,
- List<SharedLibraryInfo> sharedLibraries,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
+ final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos;
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index cced0f4a7eb2..b72e83692e8a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -28,10 +28,8 @@ import android.app.NotificationManager;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.app.admin.DevicePolicyManagerInternal;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.pm.ApplicationInfo;
@@ -141,7 +139,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private final Callbacks mCallbacks;
- private volatile boolean mBootCompleted = false;
+ private volatile boolean mOkToSendBroadcasts = false;
/**
* File storing persisted {@link #mSessions} metadata.
@@ -206,29 +204,17 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mSessionsDir.mkdirs();
mApexManager = am;
- mStagingManager = new StagingManager(pm, this, am);
- }
- private void onBootCompleted() {
- mBootCompleted = true;
- // Tell APEX manager about it as well
- mApexManager.onBootCompleted();
+ mStagingManager = new StagingManager(pm, this, am, context);
}
- boolean isBootCompleted() {
- return mBootCompleted;
+ boolean okToSendBroadcasts() {
+ return mOkToSendBroadcasts;
}
public void systemReady() {
mAppOps = mContext.getSystemService(AppOpsManager.class);
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onBootCompleted();
- mContext.unregisterReceiver(this);
- }
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
synchronized (mSessions) {
readSessionsLocked();
@@ -271,6 +257,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
for (PackageInstallerSession session : stagedSessionsToRestore) {
mStagingManager.restoreSession(session);
}
+ // Broadcasts are not sent while we restore sessions on boot, since no processes would be
+ // ready to listen to them. From now on, we greedily assume that broadcasts requests are
+ // safe to send out. The worst that can happen is that a broadcast is attempted before
+ // ActivityManagerService completes its own systemReady(), in which case it will be rejected
+ // with an otherwise harmless exception.
+ // A more appropriate way to do this would be to wait until the correct boot phase is
+ // reached, but since we are not a SystemService we can't override onBootPhase.
+ // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
+ // way either.
+ mOkToSendBroadcasts = true;
}
@GuardedBy("mSessions")
@@ -1189,7 +1185,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
public void onStagedSessionChanged(PackageInstallerSession session) {
writeSessionsAsync();
- if (mBootCompleted) {
+ if (mOkToSendBroadcasts) {
mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
session.userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7ed49fccb88d..45b3b5b1e18e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1873,7 +1873,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
mStagingManager.abortCommittedSession(this);
- //TODO(b/123624108): delete staging dir
+ cleanStageDir();
}
if (mRelinquished) {
@@ -2008,7 +2008,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Send broadcast to default launcher only if it's a new install
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
- if (success && isNewInstall && mPm.mInstallerService.isBootCompleted()) {
+ if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
mPm.sendSessionCommitBroadcast(generateInfo(), userId);
}
@@ -2096,9 +2096,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
// For staged sessions, we don't delete the directory where the packages have been copied,
- // since these packages are supposed to be read on reboot. StagingManager is in charge of
- // deleting these dirs when the staged session has reached a final state.
- // TODO(b/118865310): Implement packageDir deletion in StagingManager.
+ // since these packages are supposed to be read on reboot.
+ // Those dirs are deleted when the staged session has reached a final state.
if (stageDir != null && !params.isStaged) {
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e7e3e833d385..80e794f2593e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3101,7 +3101,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- mApexManager = new ApexManager();
+ mApexManager = new ApexManager(context);
mInstallerService = new PackageInstallerService(context, this, mApexManager);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
@@ -9413,12 +9413,12 @@ public class PackageManagerService extends IPackageManager.Stub
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
- pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
+ pdo.performDexOpt(depPackage, instructionSets,
getOrCreateCompilerPackageStats(depPackage),
mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
}
}
- return pdo.performDexOpt(p, p.usesLibraryInfos, instructionSets,
+ return pdo.performDexOpt(p, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
}
@@ -16324,7 +16324,7 @@ public class PackageManagerService extends IPackageManager.Stub
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
+ mPackageDexOptimizer.performDexOpt(pkg,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
@@ -20706,6 +20706,7 @@ public class PackageManagerService extends IPackageManager.Stub
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
+ mApexManager.systemReady();
mPackageDexOptimizer.systemReady();
getStorageManagerInternal().addExternalStoragePolicy(
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index e956b74cf214..fac383945afd 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -39,6 +39,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
@@ -68,15 +69,18 @@ public class StagingManager {
private final PackageInstallerService mPi;
private final PackageManagerService mPm;
private final ApexManager mApexManager;
+ private final PowerManager mPowerManager;
private final Handler mBgHandler;
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
- StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am) {
+ StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am,
+ Context context) {
mPm = pm;
mPi = pi;
mApexManager = am;
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mBgHandler = BackgroundThread.getHandler();
}
@@ -257,7 +261,7 @@ public class StagingManager {
+ "activated");
return;
}
- if (apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown) {
+ if (isApexSessionFailed(apexSessionInfo)) {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"APEX activation failed. Check logcat messages from apexd for "
+ "more information.");
@@ -286,6 +290,20 @@ public class StagingManager {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Staged installation of APKs failed. Check logcat messages for"
+ "more information.");
+
+ if (!hasApex) {
+ return;
+ }
+
+ if (!mApexManager.abortActiveSession()) {
+ Slog.e(TAG, "Failed to abort APEXd session");
+ } else {
+ Slog.e(TAG,
+ "Successfully aborted apexd session. Rebooting device in order to revert "
+ + "to the previous state of APEXd.");
+ mPowerManager.reboot(null);
+ }
+
return;
}
@@ -468,7 +486,13 @@ public class StagingManager {
ApexSessionInfo session = mApexManager.getStagedSessionInfo(sessionId);
/* checking if the session is in a final state, i.e., not active anymore */
- return session.isUnknown || session.isActivationFailed || session.isSuccess;
+ return session.isUnknown || session.isActivationFailed || session.isSuccess
+ || session.isRolledBack;
+ }
+
+ private static boolean isApexSessionFailed(ApexSessionInfo apexSessionInfo) {
+ return apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown
+ || apexSessionInfo.isRolledBack;
}
@GuardedBy("mStagedSessions")
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index cf026e97b69f..0db3d78fed5b 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -35,10 +35,12 @@ import com.android.server.wm.WindowManagerInternal;
/**
* Controls the behavior of foldable devices whose screen can literally bend and fold.
+ * TODO(b/126160895): Move DisplayFoldController from PhoneWindowManager to DisplayPolicy.
*/
class DisplayFoldController {
private static final String TAG = "DisplayFoldController";
+
private final WindowManagerInternal mWindowManagerInternal;
private final DisplayManagerInternal mDisplayManagerInternal;
private final int mDisplayId;
@@ -52,6 +54,8 @@ class DisplayFoldController {
private final DisplayInfo mNonOverrideDisplayInfo = new DisplayInfo();
private final RemoteCallbackList<IDisplayFoldListener> mListeners = new RemoteCallbackList<>();
private Boolean mFolded;
+ private String mFocusedApp;
+ private final DisplayFoldDurationLogger mDurationLogger = new DisplayFoldDurationLogger();
DisplayFoldController(WindowManagerInternal windowManagerInternal,
DisplayManagerInternal displayManagerInternal, int displayId, Rect foldedArea,
@@ -63,6 +67,14 @@ class DisplayFoldController {
mHandler = handler;
}
+ void finishedGoingToSleep() {
+ mDurationLogger.onFinishedGoingToSleep();
+ }
+
+ void finishedWakingUp() {
+ mDurationLogger.onFinishedWakingUp(mFolded);
+ }
+
void requestDeviceFolded(boolean folded) {
mHandler.post(() -> setDeviceFolded(folded));
}
@@ -97,6 +109,8 @@ class DisplayFoldController {
mWindowManagerInternal.clearForcedDisplaySize(mDisplayId);
mDisplayManagerInternal.setDisplayOffsets(mDisplayId, 0, 0);
}
+ mDurationLogger.setDeviceFolded(folded);
+ mDurationLogger.logFocusedAppWithFoldState(folded, mFocusedApp);
mFolded = folded;
final int n = mListeners.beginBroadcast();
@@ -167,6 +181,10 @@ class DisplayFoldController {
return result;
}
+ void onDefaultDisplayFocusChanged(String pkg) {
+ mFocusedApp = pkg;
+ }
+
static DisplayFoldController create(Context context, int displayId) {
final DisplayManagerInternal displayService =
LocalServices.getService(DisplayManagerInternal.class);
diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
new file mode 100644
index 000000000000..bdcd2cde2e4e
--- /dev/null
+++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
@@ -0,0 +1,117 @@
+/*
+ * 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.policy;
+
+import android.annotation.IntDef;
+import android.metrics.LogMaker;
+import android.os.SystemClock;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Logger for tracking duration of usage in folded vs unfolded state.
+ */
+class DisplayFoldDurationLogger {
+ static final int SCREEN_STATE_UNKNOWN = -1;
+ static final int SCREEN_STATE_OFF = 0;
+ static final int SCREEN_STATE_ON_UNFOLDED = 1;
+ static final int SCREEN_STATE_ON_FOLDED = 2;
+
+ @IntDef(flag = true, prefix = {"SCREEN_STATE_"}, value = {
+ SCREEN_STATE_UNKNOWN,
+ SCREEN_STATE_OFF,
+ SCREEN_STATE_ON_UNFOLDED,
+ SCREEN_STATE_ON_FOLDED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScreenState {}
+
+ private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
+ private Long mLastChanged = null;
+
+ private static final int LOG_SUBTYPE_UNFOLDED = 0;
+ private static final int LOG_SUBTYPE_FOLDED = 1;
+ private static final int LOG_SUBTYPE_DURATION_MASK = 0x80000000;
+
+ private final MetricsLogger mLogger = new MetricsLogger();
+
+ void onFinishedWakingUp(Boolean folded) {
+ if (folded == null) {
+ mScreenState = SCREEN_STATE_UNKNOWN;
+ } else if (folded) {
+ mScreenState = SCREEN_STATE_ON_FOLDED;
+ } else {
+ mScreenState = SCREEN_STATE_ON_UNFOLDED;
+ }
+ mLastChanged = SystemClock.uptimeMillis();
+ }
+
+ void onFinishedGoingToSleep() {
+ log();
+ mScreenState = SCREEN_STATE_OFF;
+ mLastChanged = null;
+ }
+
+ void setDeviceFolded(boolean folded) {
+ // This function is called even when the screen is in ADO mode, but we're only
+ // interested in the case that the screen is actually on.
+ if (!isOn()) {
+ return;
+ }
+ log();
+ mScreenState = folded ? SCREEN_STATE_ON_FOLDED : SCREEN_STATE_ON_UNFOLDED;
+ mLastChanged = SystemClock.uptimeMillis();
+ }
+
+ void logFocusedAppWithFoldState(boolean folded, String packageName) {
+ mLogger.write(
+ new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setSubtype(folded ? LOG_SUBTYPE_FOLDED : LOG_SUBTYPE_UNFOLDED)
+ .setPackageName(packageName));
+ }
+
+ private void log() {
+ if (mLastChanged == null) {
+ return;
+ }
+ int subtype;
+ switch (mScreenState) {
+ case SCREEN_STATE_ON_UNFOLDED:
+ subtype = LOG_SUBTYPE_UNFOLDED | LOG_SUBTYPE_DURATION_MASK;
+ break;
+ case SCREEN_STATE_ON_FOLDED:
+ subtype = LOG_SUBTYPE_FOLDED | LOG_SUBTYPE_DURATION_MASK;
+ break;
+ default:
+ return;
+ }
+ mLogger.write(
+ new LogMaker(MetricsProto.MetricsEvent.ACTION_DISPLAY_FOLD)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setSubtype(subtype)
+ .setLatency(SystemClock.uptimeMillis() - mLastChanged));
+ }
+
+ private boolean isOn() {
+ return mScreenState == SCREEN_STATE_ON_UNFOLDED || mScreenState == SCREEN_STATE_ON_FOLDED;
+ }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0759419be608..c0e597497740 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3241,6 +3241,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
+ public void onDefaultDisplayFocusChangedLw(WindowState newFocus) {
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.onDefaultDisplayFocusChanged(
+ newFocus != null ? newFocus.getOwningPackage() : null);
+ }
+ }
+
+ @Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
throws RemoteException {
synchronized (mLock) {
@@ -4440,6 +4448,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.onFinishedGoingToSleep(why,
mCameraGestureTriggeredDuringGoingToSleep);
}
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.finishedGoingToSleep();
+ }
mCameraGestureTriggeredDuringGoingToSleep = false;
}
@@ -4480,6 +4491,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onFinishedWakingUp();
}
+ if (mDisplayFoldController != null) {
+ mDisplayFoldController.finishedWakingUp();
+ }
}
private void wakeUpFromPowerKey(long eventTime) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 5cd00145821e..d58707cf2eec 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1489,6 +1489,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
}
/**
+ * A new window on default display has been focused.
+ */
+ default void onDefaultDisplayFocusChangedLw(WindowState newFocus) {}
+
+ /**
* Updates the flag about whether AOD is showing.
*
* @return whether the value was changed.
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index ae1090cfb045..c40854923bf7 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -209,11 +209,8 @@ public class KeyguardServiceDelegate {
mKeyguardState.reset();
mHandler.post(() -> {
try {
- // There are no longer any keyguard windows on secondary displays, so pass
- // {@code null}. All that means is that showWhenLocked activities on
- // external displays now get to show.
ActivityTaskManager.getService().setLockScreenShown(true /* keyguardShowing */,
- false /* aodShowing */, null /* secondaryDisplaysShowing */);
+ false /* aodShowing */);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 176dbbf6a965..89d24b194b13 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -36,6 +36,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.hardware.power.V1_0.PowerHint;
@@ -81,7 +82,6 @@ import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.EventLogTags;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index e6fa500eaef3..af78995b6faa 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -280,7 +280,7 @@ public class BatterySaverStateMachine {
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
mDynamicPowerSavingsDefaultDisableThreshold);
final boolean isStickyAutoDisableEnabled = getGlobalSetting(
- Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0;
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1) != 0;
final int stickyAutoDisableThreshold = getGlobalSetting(
Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index d2c0ee3f5196..88a5fb48ada4 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -40,6 +41,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.util.IntArray;
import android.util.Log;
@@ -47,6 +49,7 @@ import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.pm.Installer;
@@ -121,6 +124,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private final RollbackPackageHealthObserver mPackageHealthObserver;
private final AppDataRollbackHelper mAppDataRollbackHelper;
+ // This field stores the difference in Millis between the uptime (millis since device
+ // has booted) and current time (device wall clock) - it's used to update rollback data
+ // timestamps when the time is changed, by the user or by change of timezone.
+ // No need for guarding with lock because value is only accessed in handler thread.
+ private long mRelativeBootTime = calculateRelativeBootTime();
+
+
RollbackManagerServiceImpl(Context context) {
mContext = context;
// Note that we're calling onStart here because this object is only constructed on
@@ -217,6 +227,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
}, enableRollbackFilter, null, getHandler());
+
+ registerTimeChangeReceiver();
}
@Override
@@ -268,6 +280,45 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
callerPackageName, statusReceiver));
}
+ private void registerTimeChangeReceiver() {
+ final BroadcastReceiver timeChangeIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final long oldRelativeBootTime = mRelativeBootTime;
+ mRelativeBootTime = calculateRelativeBootTime();
+ final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
+
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+
+ Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
+ while (iter.hasNext()) {
+ RollbackData data = iter.next();
+
+ data.timestamp = data.timestamp.plusMillis(timeDifference);
+ try {
+ mRollbackStore.saveAvailableRollback(data);
+ } catch (IOException ioe) {
+ // TODO: figure out the right way to deal with this, especially if
+ // it fails for some data and succeeds for others.
+ Log.e(TAG, "Unable to save rollback info for : " + data.rollbackId,
+ ioe);
+ }
+ }
+
+ }
+ }
+ };
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ mContext.registerReceiver(timeChangeIntentReceiver, filter,
+ null /* broadcastPermission */, getHandler());
+ }
+
+ private static long calculateRelativeBootTime() {
+ return System.currentTimeMillis() - SystemClock.elapsedRealtime();
+ }
+
/**
* Performs the actual work to commit a rollback.
* The work is done on the current thread. This may be a long running
@@ -362,20 +413,24 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- File packageCode = RollbackStore.getPackageCode(data, info.getPackageName());
- if (packageCode == null) {
+ File[] packageCodePaths = RollbackStore.getPackageCodePaths(
+ data, info.getPackageName());
+ if (packageCodePaths == null) {
sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
- "Backup copy of package code inaccessible");
+ "Backup copy of package inaccessible");
return;
}
- try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCode,
- ParcelFileDescriptor.MODE_READ_ONLY)) {
- final long token = Binder.clearCallingIdentity();
- try {
- session.write(packageCode.getName(), 0, packageCode.length(), fd);
- } finally {
- Binder.restoreCallingIdentity(token);
+ for (File packageCodePath : packageCodePaths) {
+ try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath,
+ ParcelFileDescriptor.MODE_READ_ONLY)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ session.write(packageCodePath.getName(), 0, packageCodePath.length(),
+ fd);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
}
parentSession.addChildSessionId(sessionId);
@@ -434,7 +489,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
mAvailableRollbacks = null;
mRecentlyExecutedRollbacks = null;
}
- getHandler().post(() -> ensureRollbackDataLoaded());
+ getHandler().post(() -> {
+ updateRollbackLifetimeDurationInMillis();
+ ensureRollbackDataLoaded();
+ });
}
@Override
@@ -950,7 +1008,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
try {
- RollbackStore.backupPackageCode(data, packageName, pkgInfo.applicationInfo.sourceDir);
+ ApplicationInfo appInfo = pkgInfo.applicationInfo;
+ RollbackStore.backupPackageCodePath(data, packageName, appInfo.sourceDir);
+ if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) {
+ for (String sourceDir : appInfo.splitSourceDirs) {
+ RollbackStore.backupPackageCodePath(data, packageName, sourceDir);
+ }
+ }
} catch (IOException e) {
Log.e(TAG, "Unable to copy package for rollback for " + packageName, e);
return false;
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index be904eacebff..bb4e89eca5da 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -234,9 +234,11 @@ class RollbackStore {
}
/**
- * Creates a backup copy of the apk or apex for a package.
+ * Creates a backup copy of an apk or apex for a package.
+ * For packages containing splits, this method should be called for each
+ * of the package's split apks in addition to the base apk.
*/
- static void backupPackageCode(RollbackData data, String packageName, String codePath)
+ static void backupPackageCodePath(RollbackData data, String packageName, String codePath)
throws IOException {
File sourceFile = new File(codePath);
File targetDir = new File(data.backupDir, packageName);
@@ -248,16 +250,16 @@ class RollbackStore {
}
/**
- * Returns the apk or apex file backed up for the given package.
- * Returns null if none found.
+ * Returns the apk or apex files backed up for the given package.
+ * Includes the base apk and any splits. Returns null if none found.
*/
- static File getPackageCode(RollbackData data, String packageName) {
+ static File[] getPackageCodePaths(RollbackData data, String packageName) {
File targetDir = new File(data.backupDir, packageName);
File[] files = targetDir.listFiles();
- if (files == null || files.length != 1) {
+ if (files == null || files.length == 0) {
return null;
}
- return files[0];
+ return files;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 087de69b6c12..e976975bd675 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2751,7 +2751,9 @@ final class ActivityRecord extends ConfigurationContainer {
final Configuration srcConfig = task.getConfiguration();
overrideConfig.colorMode = srcConfig.colorMode;
overrideConfig.densityDpi = srcConfig.densityDpi;
- overrideConfig.screenLayout = srcConfig.screenLayout;
+ overrideConfig.screenLayout = srcConfig.screenLayout
+ & (Configuration.SCREENLAYOUT_LONG_MASK
+ | Configuration.SCREENLAYOUT_SIZE_MASK);
// The smallest screen width is the short side of screen bounds. Because the bounds
// and density won't be changed, smallestScreenWidthDp is also fixed.
overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cb4664f9f683..486a4ea24f65 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3098,8 +3098,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing,
- int[] secondaryDisplaysShowing) {
+ public void setLockScreenShown(boolean keyguardShowing, boolean aodShowing) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
@@ -3116,8 +3115,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mH.sendMessage(msg);
}
try {
- mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
- secondaryDisplaysShowing);
+ mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f3f507f156be..b028569ccb08 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2787,6 +2787,9 @@ public class DisplayPolicy {
public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
mFocusedWindow = newFocus;
mLastFocusedWindow = lastFocus;
+ if (mDisplayContent.isDefaultDisplay) {
+ mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
+ }
if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
// If the navigation bar has been hidden or shown, we need to do another
// layout pass to update that window.
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index b5be2ac5df98..feb711abaead 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -49,7 +49,6 @@ import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import java.io.PrintWriter;
-import java.util.Arrays;
/**
* Controls Keyguard occluding, dismissing and transitions depending on what kind of activities are
@@ -120,18 +119,15 @@ class KeyguardController {
/**
* Update the Keyguard showing state.
*/
- void setKeyguardShown(boolean keyguardShowing, boolean aodShowing,
- int[] secondaryDisplaysShowing) {
+ void setKeyguardShown(boolean keyguardShowing, boolean aodShowing) {
boolean showingChanged = keyguardShowing != mKeyguardShowing || aodShowing != mAodShowing;
// If keyguard is going away, but SystemUI aborted the transition, need to reset state.
showingChanged |= mKeyguardGoingAway && keyguardShowing;
- if (!showingChanged && Arrays.equals(secondaryDisplaysShowing,
- mSecondaryDisplayIdsShowing)) {
+ if (!showingChanged) {
return;
}
mKeyguardShowing = keyguardShowing;
mAodShowing = aodShowing;
- mSecondaryDisplayIdsShowing = secondaryDisplaysShowing;
mWindowManager.setAodShowing(aodShowing);
if (showingChanged) {
dismissDockedStackIfNeeded();
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index c6c85fde76b2..0480d438e3cd 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1159,7 +1159,8 @@ class RecentTasks {
/**
* @return whether the given active task should be presented to the user through SystemUI.
*/
- private boolean isVisibleRecentTask(TaskRecord task) {
+ @VisibleForTesting
+ boolean isVisibleRecentTask(TaskRecord task) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
+ " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
+ " sessionDuration=" + mActiveTasksSessionDurationMs
@@ -1195,6 +1196,17 @@ class RecentTasks {
}
}
+ // Tasks managed by/associated with an ActivityView should be excluded from recents.
+ // singleTaskInstance is set on the VirtualDisplay managed by ActivityView
+ // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
+ final ActivityStack stack = task.getStack();
+ if (stack != null) {
+ ActivityDisplay display = stack.getDisplay();
+ if (display != null && display.isSingleTaskInstance()) {
+ return false;
+ }
+ }
+
// If we're in lock task mode, ignore the root task
if (task == mService.getLockTaskController().getRootTask()) {
return false;
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index f3050a903c70..904c50348b2c 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -235,8 +235,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
// STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
// that legacy (pre-D) apps and those apps that can't handle multiple screen density well
// are forced to be maximized. The rest of this step is to define the default policy when
- // there is no initial bounds or a fully resolved current params from callers. Right now we
- // launch all possible tasks/activities that can handle freeform into freeform mode.
+ // there is no initial bounds or a fully resolved current params from callers.
if (display.inFreeformWindowingMode()) {
if (launchMode == WINDOWING_MODE_PINNED) {
if (DEBUG) appendLog("picture-in-picture");
@@ -247,17 +246,6 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
launchMode = WINDOWING_MODE_FULLSCREEN;
outParams.mBounds.setEmpty();
if (DEBUG) appendLog("forced-maximize");
- } else if (fullyResolvedCurrentParam) {
- // Don't adjust launch mode if that's inherited, except when we're launching an
- // activity that should be forced to maximize.
- if (DEBUG) appendLog("skip-adjustment-fully-resolved-params");
- } else if (launchMode != WINDOWING_MODE_FREEFORM
- && (isNOrGreater(root) || isPreNResizeable(root))) {
- // We're launching a pre-N and post-D activity that supports resizing, or a post-N
- // activity. They can handle freeform nicely so launch them in freeform.
- // Use undefined because we know we're in a freeform display.
- launchMode = WINDOWING_MODE_UNDEFINED;
- if (DEBUG) appendLog("should-be-freeform");
}
} else {
if (DEBUG) appendLog("non-freeform-display");
@@ -441,10 +429,6 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
return !root.isResizeable();
}
- private boolean isNOrGreater(@NonNull ActivityRecord root) {
- return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
- }
-
/**
* Resolves activity requested orientation to 4 categories:
* 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
@@ -485,10 +469,6 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
return orientation;
}
- private boolean isPreNResizeable(ActivityRecord root) {
- return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
- }
-
private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
@NonNull Rect outBounds) {
outBounds.set(srcBounds);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 76f080b233a8..05d47609de4c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1292,6 +1292,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* Called when an animation has finished running.
*/
protected void onAnimationFinished() {
+ mWmService.onAnimationFinished();
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e19c7c66815c..474a9dabf9c4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -372,6 +372,8 @@ public class WindowManagerService extends IWindowManager.Stub
private static final int TRANSITION_ANIMATION_SCALE = 1;
private static final int ANIMATION_DURATION_SCALE = 2;
+ private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
+
final WindowTracing mWindowTracing;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -7424,13 +7426,38 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
+ waitForAnimationsToComplete();
+
synchronized (mGlobalLock) {
mWindowPlacerLocked.performSurfacePlacementIfScheduled();
- new SurfaceControl.Transaction()
- .syncInputWindows()
- .apply(true);
}
+ new SurfaceControl.Transaction().syncInputWindows().apply(true);
+
return mInputManager.injectInputEvent(ev, mode);
}
+
+ private void waitForAnimationsToComplete() {
+ synchronized (mGlobalLock) {
+ long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
+ while (mRoot.isSelfOrChildAnimating() && timeoutRemaining > 0) {
+ long startTime = System.currentTimeMillis();
+ try {
+ mGlobalLock.wait(timeoutRemaining);
+ } catch (InterruptedException e) {
+ }
+ timeoutRemaining -= (System.currentTimeMillis() - startTime);
+ }
+
+ if (mRoot.isSelfOrChildAnimating()) {
+ Log.w(TAG, "Timed out waiting for animations to complete.");
+ }
+ }
+ }
+
+ void onAnimationFinished() {
+ synchronized (mGlobalLock) {
+ mGlobalLock.notifyAll();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ab1b6aeeaa8d..a13086dcc279 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4373,7 +4373,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
+ mRemoveOnExit + ", mDestroying=" + mDestroying);
- mWinAnimator.cancelExitAnimationForNextAnimationLocked();
+ // Cancel the existing exit animation for the next enter animation.
+ if (isSelfAnimating()) {
+ cancelAnimation();
+ destroySurfaceUnchecked();
+ }
mAnimatingExit = false;
}
if (mDestroying) {
@@ -4485,6 +4489,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
protected void onAnimationFinished() {
+ super.onAnimationFinished();
mWinAnimator.onAnimationFinished();
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2e2da6d11f34..969ced43b942 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -248,14 +248,6 @@ class WindowStateAnimator {
mWallpaperControllerLocked = win.getDisplayContent().mWallpaperController;
}
- void cancelExitAnimationForNextAnimationLocked() {
- if (DEBUG_ANIM) Slog.d(TAG,
- "cancelExitAnimationForNextAnimationLocked: " + mWin);
-
- mWin.cancelAnimation();
- mWin.destroySurfaceUnchecked();
- }
-
void onAnimationFinished() {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 3b17abc8732f..48b9340c4857 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -208,6 +208,7 @@ class WindowTracing {
pw.println(" frame: Log trace once per frame");
pw.println(" transaction: Log each transaction");
pw.println(" size: Set the maximum log size (in KB)");
+ pw.println(" status: Print trace status");
pw.println(" level [lvl]: Set the log level between");
pw.println(" lvl may be one of:");
pw.println(" critical: Only visible windows with reduced information");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index fe941681a7be..03240c076ede 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -36,13 +36,14 @@
#include "android_runtime/Log.h"
#include <arpa/inet.h>
+#include <cinttypes>
+#include <iomanip>
#include <limits>
#include <linux/in.h>
#include <linux/in6.h>
#include <pthread.h>
#include <string.h>
-#include <cinttypes>
-#include <iomanip>
+#include <utils/SystemClock.h>
static jobject mCallbacksObj = nullptr;
@@ -111,10 +112,9 @@ using android::hardware::Void;
using android::hardware::hidl_vec;
using android::hardware::hidl_string;
using android::hardware::hidl_death_recipient;
+
using android::hardware::gnss::V1_0::GnssConstellationType;
-using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::V1_0::GnssLocationFlags;
-
using android::hardware::gnss::V1_0::IAGnssRilCallback;
using android::hardware::gnss::V1_0::IGnssBatching;
using android::hardware::gnss::V1_0::IGnssBatchingCallback;
@@ -128,13 +128,17 @@ using android::hardware::gnss::V1_0::IGnssNiCallback;
using android::hardware::gnss::V1_0::IGnssXtra;
using android::hardware::gnss::V1_0::IGnssXtraCallback;
+using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
using android::hardware::gnss::V2_0::IGnssCallback;
+
using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
using android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using android::hidl::base::V1_0::IBase;
+using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
@@ -204,6 +208,20 @@ sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
namespace android {
+namespace {
+
+// Returns true if location has lat/long information.
+bool hasLatLong(const GnssLocation_V1_0& location) {
+ return (static_cast<uint32_t>(location.gnssLocationFlags) &
+ GnssLocationFlags::HAS_LAT_LONG) != 0;
+}
+
+// Returns true if location has lat/long information.
+bool hasLatLong(const GnssLocation_V2_0& location) {
+ return hasLatLong(location.v1_0);
+}
+
+} // namespace
template<class T>
class JavaMethodHelper {
public:
@@ -216,7 +234,7 @@ class JavaMethodHelper {
T value);
private:
- static const char *const signature_;
+ static const char* const signature_;
};
template<class T>
@@ -234,6 +252,8 @@ class JavaObject {
public:
JavaObject(JNIEnv* env, const char* class_name);
JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_1);
+ JavaObject(JNIEnv* env, const char* class_name, jobject object);
+
virtual ~JavaObject();
template<class T>
@@ -260,6 +280,11 @@ JavaObject::JavaObject(JNIEnv* env, const char* class_name, const char * sz_arg_
object_ = env_->NewObject(clazz_, ctor, env->NewStringUTF(sz_arg_1));
}
+JavaObject::JavaObject(JNIEnv* env, const char* class_name, jobject object)
+ : env_(env), object_(object) {
+ clazz_ = env_->FindClass(class_name);
+}
+
JavaObject::~JavaObject() {
env_->DeleteLocalRef(clazz_);
}
@@ -303,6 +328,8 @@ const char *const JavaMethodHelper<uint32_t>::signature_ = "(I)V";
template<>
const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
template<>
+const char *const JavaMethodHelper<uint64_t>::signature_ = "(J)V";
+template<>
const char *const JavaMethodHelper<float>::signature_ = "(F)V";
template<>
const char *const JavaMethodHelper<double>::signature_ = "(D)V";
@@ -416,7 +443,8 @@ static JNIEnv* getJniEnv() {
return env;
}
-static jobject translateLocation(JNIEnv* env, const GnssLocation& location) {
+static jobject translateGnssLocation(JNIEnv* env,
+ const GnssLocation_V1_0& location) {
JavaObject object(env, "android/location/Location", "gps");
uint16_t flags = static_cast<uint32_t>(location.gnssLocationFlags);
@@ -446,23 +474,33 @@ static jobject translateLocation(JNIEnv* env, const GnssLocation& location) {
SET(BearingAccuracyDegrees, location.bearingAccuracyDegrees);
}
SET(Time, location.timestamp);
+ SET(ElapsedRealtimeNanos, android::elapsedRealtimeNano());
return object.get();
}
-static GnssLocation createGnssLocation(
- jint gnssLocationFlags,
- jdouble latitudeDegrees,
- jdouble longitudeDegrees,
- jdouble altitudeMeters,
- jfloat speedMetersPerSec,
- jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters,
- jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond,
- jfloat bearingAccuracyDegrees,
+static jobject translateGnssLocation(JNIEnv* env,
+ const GnssLocation_V2_0& location) {
+ JavaObject object(env, "android/location/Location",
+ translateGnssLocation(env, location.v1_0));
+
+ const uint16_t flags = static_cast<uint16_t>(location.elapsedRealtime.flags);
+
+ // Overwrite ElapsedRealtimeNanos when available from HAL.
+ if (flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) {
+ SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs);
+ }
+
+ return object.get();
+}
+
+static GnssLocation_V1_0 createGnssLocation_V1_0(
+ jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
+ jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
jlong timestamp) {
- GnssLocation location;
+ GnssLocation_V1_0 location;
location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
location.latitudeDegrees = static_cast<double>(latitudeDegrees);
location.longitudeDegrees = static_cast<double>(longitudeDegrees);
@@ -478,11 +516,30 @@ static GnssLocation createGnssLocation(
return location;
}
+static GnssLocation_V2_0 createGnssLocation_V2_0(
+ jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
+ jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos) {
+ GnssLocation_V2_0 location;
+ location.v1_0 = createGnssLocation_V1_0(
+ gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
+ speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond,
+ bearingAccuracyDegrees, timestamp);
+
+ location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+
+ return location;
+}
+
/*
* GnssCallback class implements the callback methods for IGnss interface.
*/
struct GnssCallback : public IGnssCallback {
- Return<void> gnssLocationCb(const GnssLocation& location) override;
+ Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
@@ -496,7 +553,13 @@ struct GnssCallback : public IGnssCallback {
// New in 1.1
Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+ // New in 2.0
Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+ Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
+
+ // Templated implementation for gnnsLocationCb and gnnsLocationCb_2_0.
+ template <class T>
+ Return<void> gnssLocationCbImpl(const T& location);
// TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics
static const char* sNmeaString;
@@ -517,22 +580,30 @@ Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name
const char* GnssCallback::sNmeaString = nullptr;
size_t GnssCallback::sNmeaStringLength = 0;
-Return<void> GnssCallback::gnssLocationCb(const GnssLocation& location) {
+template<class T>
+Return<void> GnssCallback::gnssLocationCbImpl(const T& location) {
JNIEnv* env = getJniEnv();
- jobject jLocation = translateLocation(env, location);
- bool hasLatLong = (static_cast<uint32_t>(location.gnssLocationFlags) &
- GnssLocationFlags::HAS_LAT_LONG) != 0;
+ jobject jLocation = translateGnssLocation(env, location);
env->CallVoidMethod(mCallbacksObj,
method_reportLocation,
- boolToJbool(hasLatLong),
+ boolToJbool(hasLatLong(location)),
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(jLocation);
return Void();
}
+Return<void> GnssCallback::gnssLocationCb(const GnssLocation_V1_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V1_0>(location);
+}
+
+Return<void>
+GnssCallback::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V2_0>(location);
+}
+
Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
@@ -681,12 +752,13 @@ struct GnssGeofenceCallback : public IGnssGeofenceCallback {
// Methods from ::android::hardware::gps::V1_0::IGnssGeofenceCallback follow.
Return<void> gnssGeofenceTransitionCb(
int32_t geofenceId,
- const GnssLocation& location,
+ const GnssLocation_V1_0& location,
GeofenceTransition transition,
hardware::gnss::V1_0::GnssUtcTime timestamp) override;
- Return<void> gnssGeofenceStatusCb(
+ Return<void>
+ gnssGeofenceStatusCb(
GeofenceAvailability status,
- const GnssLocation& location) override;
+ const GnssLocation_V1_0& location) override;
Return<void> gnssGeofenceAddCb(int32_t geofenceId,
GeofenceStatus status) override;
Return<void> gnssGeofenceRemoveCb(int32_t geofenceId,
@@ -698,13 +770,12 @@ struct GnssGeofenceCallback : public IGnssGeofenceCallback {
};
Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
- int32_t geofenceId,
- const GnssLocation& location,
+ int32_t geofenceId, const GnssLocation_V1_0& location,
GeofenceTransition transition,
hardware::gnss::V1_0::GnssUtcTime timestamp) {
JNIEnv* env = getJniEnv();
- jobject jLocation = translateLocation(env, location);
+ jobject jLocation = translateGnssLocation(env, location);
env->CallVoidMethod(mCallbacksObj,
method_reportGeofenceTransition,
@@ -718,16 +789,14 @@ Return<void> GnssGeofenceCallback::gnssGeofenceTransitionCb(
return Void();
}
-Return<void> GnssGeofenceCallback::gnssGeofenceStatusCb(
- GeofenceAvailability status,
- const GnssLocation& location) {
+Return<void>
+GnssGeofenceCallback::gnssGeofenceStatusCb(GeofenceAvailability status,
+ const GnssLocation_V1_0& location) {
JNIEnv* env = getJniEnv();
- jobject jLocation = translateLocation(env, location);
+ jobject jLocation = translateGnssLocation(env, location);
- env->CallVoidMethod(mCallbacksObj,
- method_reportGeofenceStatus,
- status,
+ env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(jLocation);
@@ -1296,18 +1365,18 @@ struct GnssBatchingCallback : public IGnssBatchingCallback {
* Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
* follow.
*/
- Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations)
- override;
+ Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation_V1_0>& locations) override;
};
-Return<void> GnssBatchingCallback::gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations) {
+Return<void> GnssBatchingCallback::gnssLocationBatchCb(
+ const hidl_vec<GnssLocation_V1_0>& locations) {
JNIEnv* env = getJniEnv();
jobjectArray jLocations = env->NewObjectArray(locations.size(),
env->FindClass("android/location/Location"), nullptr);
for (uint16_t i = 0; i < locations.size(); ++i) {
- jobject jLocation = translateLocation(env, locations[i]);
+ jobject jLocation = translateGnssLocation(env, locations[i]);
env->SetObjectArrayElement(jLocations, i, jLocation);
env->DeleteLocalRef(jLocation);
}
@@ -1760,7 +1829,7 @@ static void android_location_GnssLocationProvider_agps_set_reference_location_ce
agnssRilIface->setRefLocation(location);
}
-static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */,
jint type, jstring setid_string) {
if (agnssRilIface == nullptr) {
ALOGE("no AGPS RIL interface in agps_set_id");
@@ -1806,9 +1875,34 @@ static void android_location_GnssLocationProvider_inject_best_location(
jfloat verticalAccuracyMeters,
jfloat speedAccuracyMetersPerSecond,
jfloat bearingAccuracyDegrees,
- jlong timestamp) {
+ jlong timestamp,
+ jint elapsedRealtimeFlags,
+ jlong elapsedRealtimeNanos) {
+ if (gnssHal_V2_0 != nullptr) {
+ GnssLocation_V2_0 location = createGnssLocation_V2_0(
+ gnssLocationFlags,
+ latitudeDegrees,
+ longitudeDegrees,
+ altitudeMeters,
+ speedMetersPerSec,
+ bearingDegrees,
+ horizontalAccuracyMeters,
+ verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond,
+ bearingAccuracyDegrees,
+ timestamp,
+ elapsedRealtimeFlags,
+ elapsedRealtimeNanos);
+ auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
+
+ if (!result.isOk() || !result) {
+ ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
+ }
+ return;
+ }
+
if (gnssHal_V1_1 != nullptr) {
- GnssLocation location = createGnssLocation(
+ GnssLocation_V1_0 location = createGnssLocation_V1_0(
gnssLocationFlags,
latitudeDegrees,
longitudeDegrees,
@@ -1821,12 +1915,14 @@ static void android_location_GnssLocationProvider_inject_best_location(
bearingAccuracyDegrees,
timestamp);
auto result = gnssHal_V1_1->injectBestLocation(location);
+
if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
}
- } else {
- ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
+ return;
}
+
+ ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
}
static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
@@ -2695,45 +2791,36 @@ static const JNINativeMethod sMethods[] = {
{"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
{"native_cleanup", "()V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_cleanup)},
- {"native_set_position_mode",
- "(IIIIIZ)Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
- {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
- {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
- {"native_delete_aiding_data",
- "(I)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_delete_aiding_data)},
+ {"native_set_position_mode", "(IIIIIZ)Z", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_set_position_mode)},
+ {"native_start", "()Z", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_start)},
+ {"native_stop", "()Z", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_stop)},
+ {"native_delete_aiding_data", "(I)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_delete_aiding_data)},
{"native_read_nmea", "([BI)I", reinterpret_cast<void *>(
android_location_GnssLocationProvider_read_nmea)},
{"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_time)},
- {"native_inject_best_location",
- "(IDDDFFFFFFJ)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)},
- {"native_inject_location",
- "(DDF)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)},
+ {"native_inject_best_location", "(IDDDFFFFFFJIJ)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_inject_best_location)},
+ {"native_inject_location", "(DDF)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_inject_location)},
{"native_supports_xtra", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_supports_xtra)},
- {"native_inject_xtra_data",
- "([BI)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_xtra_data)},
- {"native_agps_set_id",
- "(ILjava/lang/String;)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_set_id)},
- {"native_agps_set_ref_location_cellid",
- "(IIIII)V",
- reinterpret_cast<void *>(
- android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
- {"native_set_agps_server",
- "(ILjava/lang/String;I)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_set_agps_server)},
- {"native_send_ni_response",
- "(II)V",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_send_ni_response)},
- {"native_get_internal_state",
- "()Ljava/lang/String;",
- reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
+ {"native_inject_xtra_data", "([BI)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_inject_xtra_data)},
+ {"native_agps_set_id", "(ILjava/lang/String;)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_agps_set_id)},
+ {"native_agps_set_ref_location_cellid", "(IIIII)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
+ {"native_set_agps_server", "(ILjava/lang/String;I)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_set_agps_server)},
+ {"native_send_ni_response", "(II)V", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_send_ni_response)},
+ {"native_get_internal_state", "()Ljava/lang/String;", reinterpret_cast<void *>(
+ android_location_GnssLocationProvider_get_internal_state)},
{"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast<void *>(
android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
};
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3070488cb713..f496e817bc6c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5046,7 +5046,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
quality = PASSWORD_QUALITY_UNSPECIFIED;
}
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
+ // TODO(b/120484642): remove getBytes() below
+ final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes());
final int realQuality = metrics.quality;
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
@@ -5133,16 +5134,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
try {
if (token == null) {
if (!TextUtils.isEmpty(password)) {
- mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
+ mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
+ userHandle);
} else {
mLockPatternUtils.clearLock(null, userHandle);
}
result = true;
} else {
- result = mLockPatternUtils.setLockCredentialWithToken(password,
- TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
- : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- quality, tokenHandle, token, userHandle);
+ if (!TextUtils.isEmpty(password)) {
+ result = mLockPatternUtils.setLockCredentialWithToken(password.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ quality, tokenHandle, token, userHandle);
+ } else {
+ result = mLockPatternUtils.setLockCredentialWithToken(null,
+ LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ quality, tokenHandle, token, userHandle);
+ }
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index ebc816dc45da..782196dc0048 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -23,6 +23,7 @@ android_test {
"androidx.test.runner",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
+ "truth-prebuilt",
],
libs: [
diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index 63015be6ef3f..d32f1f77b88f 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -28,28 +28,24 @@ import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
import static com.android.server.am.ActivityManagerService.Injector;
import static com.android.server.am.AppCompactor.compactActionIntToString;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.DeviceConfig;
-import android.support.test.uiautomator.UiDevice;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.appop.AppOpsService;
+import com.android.server.testables.TestableDeviceConfig;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
-import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -59,42 +55,21 @@ import java.util.concurrent.TimeUnit;
* Build/Install/Run:
* atest FrameworksServicesTests:AppCompactorTest
*/
-@RunWith(AndroidJUnit4.class)
+@RunWith(MockitoJUnitRunner.class)
public final class AppCompactorTest {
- private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
- "device_config delete activity_manager";
-
- @Mock private AppOpsService mAppOpsService;
+ @Mock
+ private AppOpsService mAppOpsService;
private AppCompactor mCompactorUnderTest;
private HandlerThread mHandlerThread;
private Handler mHandler;
private CountDownLatch mCountDown;
- private static void clearDeviceConfig() throws IOException {
- UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_USE_COMPACTION);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4);
- uiDevice.executeShellCommand(
- CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE);
- }
+ @Rule
+ public TestableDeviceConfig mDeviceConfig = new TestableDeviceConfig();
@Before
- public void setUp() throws IOException {
- MockitoAnnotations.initMocks(this);
- clearDeviceConfig();
+ public void setUp() {
mHandlerThread = new HandlerThread("");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
@@ -111,38 +86,37 @@ public final class AppCompactorTest {
}
@After
- public void tearDown() throws IOException {
+ public void tearDown() {
mHandlerThread.quit();
mCountDown = null;
- clearDeviceConfig();
}
@Test
public void init_setsDefaults() {
mCompactorUnderTest.init();
- assertThat(mCompactorUnderTest.useCompaction(),
- is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
- assertThat(mCompactorUnderTest.mCompactActionSome, is(
- compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1)));
- assertThat(mCompactorUnderTest.mCompactActionFull, is(
- compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2)));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
- assertThat(mCompactorUnderTest.mStatsdSampleRate,
- is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
+ assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
+ AppCompactor.DEFAULT_USE_COMPACTION);
+ assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
+ assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
+ AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
}
@Test
public void init_withDeviceConfigSetsParameters() {
// When the DeviceConfig already has a flag value stored (note this test will need to
// change if the default value changes from false).
- assertThat(mCompactorUnderTest.DEFAULT_USE_COMPACTION, is(false));
+ assertThat(AppCompactor.DEFAULT_USE_COMPACTION).isFalse();
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "true", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
@@ -169,62 +143,63 @@ public final class AppCompactorTest {
// Then calling init will read and set that flag.
mCompactorUnderTest.init();
- assertThat(mCompactorUnderTest.useCompaction(), is(true));
- assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
-
- assertThat(mCompactorUnderTest.mCompactActionSome,
- is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1)));
- assertThat(mCompactorUnderTest.mCompactActionFull,
- is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1)));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
- assertThat(mCompactorUnderTest.mStatsdSampleRate,
- is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
+ assertThat(mCompactorUnderTest.useCompaction()).isTrue();
+ assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
+
+ assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
+ compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1));
+ assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
+ compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1));
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
+ AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
}
@Test
public void useCompaction_listensToDeviceConfigChanges() throws InterruptedException {
- assertThat(mCompactorUnderTest.useCompaction(),
- is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
+ assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
+ AppCompactor.DEFAULT_USE_COMPACTION);
// When we call init and change some the flag value...
mCompactorUnderTest.init();
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "true", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that new flag value is updated in the implementation.
- assertThat(mCompactorUnderTest.useCompaction(), is(true));
- assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
+ assertThat(mCompactorUnderTest.useCompaction()).isTrue();
+ assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
// And again, setting the flag the other way.
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "false", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
- assertThat(mCompactorUnderTest.useCompaction(), is(false));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.useCompaction()).isFalse();
}
@Test
public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
- assertThat(mCompactorUnderTest.useCompaction(),
- is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
+ assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
+ AppCompactor.DEFAULT_USE_COMPACTION);
mCompactorUnderTest.init();
// When we push an invalid flag value...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "foobar", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then we set the default.
- assertThat(mCompactorUnderTest.useCompaction(), is(AppCompactor.DEFAULT_USE_COMPACTION));
+ assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
+ AppCompactor.DEFAULT_USE_COMPACTION);
}
@Test
@@ -236,19 +211,19 @@ public final class AppCompactorTest {
// There are four possible values for compactAction[Some|Full].
for (int i = 1; i < 5; i++) {
mCountDown = new CountDownLatch(2);
- int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
+ int expectedSome = (AppCompactor.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
- int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
+ int expectedFull = (AppCompactor.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the updates are reflected in the flags.
- assertThat(mCompactorUnderTest.mCompactActionSome,
- is(compactActionIntToString(expectedSome)));
- assertThat(mCompactorUnderTest.mCompactActionFull,
- is(compactActionIntToString(expectedFull)));
+ assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
+ compactActionIntToString(expectedSome));
+ assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
+ compactActionIntToString(expectedFull));
}
}
@@ -262,25 +237,25 @@ public final class AppCompactorTest {
KEY_COMPACT_ACTION_1, "foo", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, "foo", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the default values are reflected in the flag
- assertThat(mCompactorUnderTest.mCompactActionSome,
- is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
- assertThat(mCompactorUnderTest.mCompactActionFull,
- is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
+ assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
+ assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
mCountDown = new CountDownLatch(2);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_1, "", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, "", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
- assertThat(mCompactorUnderTest.mCompactActionSome,
- is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
- assertThat(mCompactorUnderTest.mCompactActionFull,
- is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
+ assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
+ assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
+ compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
}
@Test
@@ -301,22 +276,22 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_4,
Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then those flags values are reflected in the compactor.
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
}
@Test
public void compactThrottle_listensToDeviceConfigChangesBadValues()
- throws IOException, InterruptedException {
+ throws InterruptedException {
mCompactorUnderTest.init();
// When one of the throttles is overridden with a bad value...
@@ -324,58 +299,55 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_1, "foo", false);
// Then all the throttles have the defaults set.
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
- clearDeviceConfig();
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
// Repeat for each of the throttle keys.
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_2, "foo", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
- clearDeviceConfig();
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_3, "foo", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
- clearDeviceConfig();
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_4, "foo", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
- assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
- assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
- assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
- is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
}
@Test
@@ -387,11 +359,11 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that override is reflected in the compactor.
- assertThat(mCompactorUnderTest.mStatsdSampleRate,
- is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
+ AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
}
@Test
@@ -403,11 +375,11 @@ public final class AppCompactorTest {
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that override is reflected in the compactor.
- assertThat(mCompactorUnderTest.mStatsdSampleRate,
- is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
+ AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
}
@Test
@@ -420,19 +392,19 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(-1.0f), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the values is capped in the range.
- assertThat(mCompactorUnderTest.mStatsdSampleRate, is(0.0f));
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(0.0f);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(1.01f), false);
- assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the values is capped in the range.
- assertThat(mCompactorUnderTest.mStatsdSampleRate, is(1.0f));
+ assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(1.0f);
}
private class TestInjector extends Injector {
diff --git a/services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
index 0fd59216fa21..5db8867658be 100644
--- a/services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.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.
@@ -16,52 +16,98 @@
package com.android.server.am;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
import android.content.ContentResolver;
+import android.os.SystemProperties;
import android.provider.Settings;
-import android.test.mock.MockContentResolver;
import android.text.TextUtils;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
/**
- * Tests for {@link SettingsToPropertiesMapper}
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:SettingsToPropertiesMapperTest
+ * Test SettingsToPropertiesMapper.
*/
-@RunWith(AndroidJUnit4.class)
-@SmallTest
public class SettingsToPropertiesMapperTest {
private static final String NAME_VALID_CHARACTERS_REGEX = "^[\\w\\-@:]*$";
private static final String[] TEST_MAPPING = new String[] {
Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS
};
- private TestMapper mTestMapper;
- private MockContentResolver mMockContentResolver;
+ private MockitoSession mSession;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private ContentResolver mMockContentResolver;
+
+ private SettingsToPropertiesMapper mTestMapper;
+
+ private HashMap<String, String> mSystemSettingsMap;
+ private HashMap<String, String> mGlobalSettingsMap;
@Before
- public void setupForEach() {
- // Use FakeSettingsProvider to not affect global state
- mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getContext());
- mMockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
- mTestMapper = new TestMapper(mMockContentResolver);
+ public void setUp() throws Exception {
+ mSession =
+ ExtendedMockito.mockitoSession().initMocks(
+ this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(SystemProperties.class)
+ .spyStatic(Settings.Global.class)
+ .spyStatic(SettingsToPropertiesMapper.class)
+ .startMocking();
+ mSystemSettingsMap = new HashMap<>();
+ mGlobalSettingsMap = new HashMap<>();
+
+ // Mock SystemProperties setter and various getters
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+ String value = invocationOnMock.getArgument(1);
+
+ mSystemSettingsMap.put(key, value);
+ return null;
+ }
+ ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+ doAnswer((Answer<String>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(0);
+
+ String storedValue = mSystemSettingsMap.get(key);
+ return storedValue == null ? "" : storedValue;
+ }
+ ).when(() -> SystemProperties.get(anyString()));
+
+ // Mock Settings.Global methods
+ doAnswer((Answer<String>) invocationOnMock -> {
+ String key = invocationOnMock.getArgument(1);
+
+ return mGlobalSettingsMap.get(key);
+ }
+ ).when(() -> Settings.Global.getString(any(), anyString()));
+
+ mTestMapper = new SettingsToPropertiesMapper(
+ mMockContentResolver, TEST_MAPPING, new String[] {});
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mSession.finishMocking();
}
@Test
@@ -108,30 +154,27 @@ public class SettingsToPropertiesMapperTest {
@Test
public void testUpdatePropertiesFromSettings() {
- Settings.Global.putString(mMockContentResolver,
- Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue");
+ mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue");
String systemPropertyName = "persist.device_config.global_settings."
+ "sqlite_compatibility_wal_flags";
mTestMapper.updatePropertiesFromSettings();
- String propValue = mTestMapper.systemPropertiesGet(systemPropertyName);
+ String propValue = mSystemSettingsMap.get(systemPropertyName);
Assert.assertEquals("testValue", propValue);
- Settings.Global.putString(mMockContentResolver,
- Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2");
+ mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2");
mTestMapper.updatePropertyFromSetting(
Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
systemPropertyName);
- propValue = mTestMapper.systemPropertiesGet(systemPropertyName);
+ propValue = mSystemSettingsMap.get(systemPropertyName);
Assert.assertEquals("testValue2", propValue);
- Settings.Global.putString(mMockContentResolver,
- Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null);
+ mGlobalSettingsMap.put(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null);
mTestMapper.updatePropertyFromSetting(
Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS,
systemPropertyName);
- propValue = mTestMapper.systemPropertiesGet(systemPropertyName);
+ propValue = mSystemSettingsMap.get(systemPropertyName);
Assert.assertEquals("", propValue);
}
@@ -163,71 +206,37 @@ public class SettingsToPropertiesMapperTest {
public void testUpdatePropertiesFromSettings_PropertyAndSettingNotPresent() {
// Test that empty property will not not be set if setting is not set
mTestMapper.updatePropertiesFromSettings();
- String propValue = mTestMapper.systemPropertiesGet("TestProperty");
+ String propValue = mSystemSettingsMap.get("TestProperty");
Assert.assertNull("Property should not be set if setting is null", propValue);
}
@Test
public void testIsNativeFlagsResetPerformed() {
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "true");
+ mSystemSettingsMap.put("device_config.reset_performed", "true");
Assert.assertTrue(mTestMapper.isNativeFlagsResetPerformed());
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "false");
+ mSystemSettingsMap.put("device_config.reset_performed", "false");
Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed());
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "");
+ mSystemSettingsMap.put("device_config.reset_performed", "");
Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed());
}
@Test
public void testGetResetNativeCategories() {
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "");
- Assert.assertEquals(mTestMapper.getResetNativeCategories().length, 0);
+ doReturn("persist.device_config.category1.flag;"
+ + "persist.device_config.category2.flag;persist.device_config.category3.flag;"
+ + "persist.device_config.category3.flag2")
+ .when(() -> SettingsToPropertiesMapper.getResetFlagsFileContent());
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "true");
- mTestMapper.setFileContent("");
+ mSystemSettingsMap.put("device_config.reset_performed", "");
Assert.assertEquals(mTestMapper.getResetNativeCategories().length, 0);
- mTestMapper.systemPropertiesSet("device_config.reset_performed", "true");
- mTestMapper.setFileContent("persist.device_config.category1.flag;"
- + "persist.device_config.category2.flag;persist.device_config.category3.flag;"
- + "persist.device_config.category3.flag2");
+ mSystemSettingsMap.put("device_config.reset_performed", "true");
List<String> categories = Arrays.asList(mTestMapper.getResetNativeCategories());
Assert.assertEquals(3, categories.size());
Assert.assertTrue(categories.contains("category1"));
Assert.assertTrue(categories.contains("category2"));
Assert.assertTrue(categories.contains("category3"));
}
-
- private static class TestMapper extends SettingsToPropertiesMapper {
- private final Map<String, String> mProps = new HashMap<>();
-
- private String mFileContent = "";
-
- TestMapper(ContentResolver contentResolver) {
- super(contentResolver, TEST_MAPPING, new String[] {});
- }
-
- @Override
- protected String systemPropertiesGet(String key) {
- Preconditions.checkNotNull(key);
- return mProps.get(key);
- }
-
- @Override
- protected void systemPropertiesSet(String key, String value) {
- Preconditions.checkNotNull(value);
- Preconditions.checkNotNull(key);
- mProps.put(key, value);
- }
-
- protected void setFileContent(String fileContent) {
- mFileContent = fileContent;
- }
-
- @Override
- protected String getResetFlagsFileContent() {
- return mFileContent;
- }
- }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
new file mode 100644
index 000000000000..b76682269c2e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfig.java
@@ -0,0 +1,131 @@
+/*
+ * 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.testables;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+
+import android.provider.DeviceConfig;
+import android.util.Pair;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+
+import org.junit.rules.TestRule;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * TestableDeviceConfig uses ExtendedMockito to replace the real implementation of DeviceConfig
+ * with essentially a local HashMap in the callers process. This allows for unit testing that do not
+ * modify the real DeviceConfig on the device at all.
+ *
+ * <p>TestableDeviceConfig should be defined as a rule on your test so it can clean up after itself.
+ * Like the following:</p>
+ * <pre class="prettyprint">
+ * &#064;Rule
+ * public final TestableDeviceConfig mTestableDeviceConfig = new TestableDeviceConfig();
+ * </pre>
+ */
+public final class TestableDeviceConfig implements TestRule {
+
+ private StaticMockitoSession mMockitoSession;
+ private Map<DeviceConfig.OnPropertyChangedListener, Pair<String, Executor>>
+ mOnPropertyChangedListenerMap = new HashMap<>();
+ private Map<String, String> mKeyValueMap = new ConcurrentHashMap<>();
+
+ /**
+ * Clears out all local overrides.
+ */
+ public void clearDeviceConfig() {
+ mKeyValueMap.clear();
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DeviceConfig.class)
+ .startMocking();
+
+ doAnswer((Answer<Void>) invocationOnMock -> {
+ String namespace = invocationOnMock.getArgument(0);
+ Executor executor = invocationOnMock.getArgument(1);
+ DeviceConfig.OnPropertyChangedListener onPropertyChangedListener =
+ invocationOnMock.getArgument(2);
+ mOnPropertyChangedListenerMap.put(
+ onPropertyChangedListener, new Pair<>(namespace, executor));
+ return null;
+ }).when(() -> DeviceConfig.addOnPropertyChangedListener(
+ anyString(), any(Executor.class),
+ any(DeviceConfig.OnPropertyChangedListener.class)));
+
+ doAnswer((Answer<Boolean>) invocationOnMock -> {
+ String namespace = invocationOnMock.getArgument(0);
+ String name = invocationOnMock.getArgument(1);
+ String value = invocationOnMock.getArgument(2);
+ mKeyValueMap.put(getKey(namespace, name), value);
+ for (DeviceConfig.OnPropertyChangedListener listener :
+ mOnPropertyChangedListenerMap.keySet()) {
+ if (namespace.equals(mOnPropertyChangedListenerMap.get(listener).first)) {
+ mOnPropertyChangedListenerMap.get(listener).second.execute(
+ () -> listener.onPropertyChanged(namespace, name, value));
+ }
+ }
+ return true;
+ }
+ ).when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), anyBoolean()));
+
+ doAnswer((Answer<String>) invocationOnMock -> {
+ String namespace = invocationOnMock.getArgument(0);
+ String name = invocationOnMock.getArgument(1);
+ return mKeyValueMap.get(getKey(namespace, name));
+ }).when(() -> DeviceConfig.getProperty(anyString(), anyString()));
+
+
+ return new TestWatcher() {
+ @Override
+ protected void succeeded(Description description) {
+ mMockitoSession.finishMocking();
+ mOnPropertyChangedListenerMap.clear();
+ }
+
+ @Override
+ protected void failed(Throwable e, Description description) {
+ mMockitoSession.finishMocking(e);
+ mOnPropertyChangedListenerMap.clear();
+ }
+ }.apply(base, description);
+ }
+
+ private static String getKey(String namespace, String name) {
+ return namespace + "/" + name;
+ }
+
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
new file mode 100644
index 000000000000..39b5840f12d8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/testables/TestableDeviceConfigTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.testables;
+
+import static android.provider.DeviceConfig.OnPropertyChangedListener;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityThread;
+import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/** Tests that ensure appropriate settings are backed up. */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TestableDeviceConfigTest {
+ private static final String sNamespace = "namespace1";
+ private static final String sKey = "key1";
+ private static final String sValue = "value1";
+ private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
+
+ @Rule
+ public TestableDeviceConfig mTestableDeviceConfig = new TestableDeviceConfig();
+
+ @Test
+ public void getProperty_empty() {
+ String result = DeviceConfig.getProperty(sNamespace, sKey);
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void setAndGetProperty_sameNamespace() {
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ String result = DeviceConfig.getProperty(sNamespace, sKey);
+ assertThat(result).isEqualTo(sValue);
+ }
+
+ @Test
+ public void setAndGetProperty_differentNamespace() {
+ String newNamespace = "namespace2";
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ String result = DeviceConfig.getProperty(newNamespace, sKey);
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void setAndGetProperty_multipleNamespaces() {
+ String newNamespace = "namespace2";
+ String newValue = "value2";
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ DeviceConfig.setProperty(newNamespace, sKey, newValue, false);
+ String result = DeviceConfig.getProperty(sNamespace, sKey);
+ assertThat(result).isEqualTo(sValue);
+ result = DeviceConfig.getProperty(newNamespace, sKey);
+ assertThat(result).isEqualTo(newValue);
+ }
+
+ @Test
+ public void setAndGetProperty_overrideValue() {
+ String newValue = "value2";
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ DeviceConfig.setProperty(sNamespace, sKey, newValue, false);
+ String result = DeviceConfig.getProperty(sNamespace, sKey);
+ assertThat(result).isEqualTo(newValue);
+ }
+
+ @Test
+ public void testListener() throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ OnPropertyChangedListener changeListener = (namespace, name, value) -> {
+ assertThat(namespace).isEqualTo(sNamespace);
+ assertThat(name).isEqualTo(sKey);
+ assertThat(value).isEqualTo(sValue);
+ countDownLatch.countDown();
+ };
+ try {
+ DeviceConfig.addOnPropertyChangedListener(sNamespace,
+ ActivityThread.currentApplication().getMainExecutor(), changeListener);
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ } finally {
+ DeviceConfig.removeOnPropertyChangedListener(changeListener);
+ }
+ }
+
+}
+
+
diff --git a/services/tests/rescueparty/how_to_run.txt b/services/tests/rescueparty/how_to_run.txt
index 9528d39358eb..a3a26d6ccaa7 100644
--- a/services/tests/rescueparty/how_to_run.txt
+++ b/services/tests/rescueparty/how_to_run.txt
@@ -1,4 +1,3 @@
-# Per http://go/westworld-local-development#step3-test-atom-and-metric-locally-on-device ,
# In one terminal:
make statsd_testdrive
./out/host/linux-x86/bin/statsd_testdrive 122
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index de782a52eb53..4293247e7d0c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4167,7 +4167,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.isResetPasswordTokenActive(admin1));
// test reset password with token
- when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
+ when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password.getBytes()),
eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token),
eq(UserHandle.USER_SYSTEM)))
@@ -5214,7 +5214,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.thenReturn(DpmMockContext.CALLER_USER_HANDLE);
dpms.mUserPasswordMetrics.put(
DpmMockContext.CALLER_USER_HANDLE,
- PasswordMetrics.computeForPassword("asdf"));
+ PasswordMetrics.computeForPassword("asdf".getBytes()));
assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity());
}
@@ -5231,10 +5231,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpms.mUserPasswordMetrics.put(
DpmMockContext.CALLER_USER_HANDLE,
- PasswordMetrics.computeForPassword("asdf"));
+ PasswordMetrics.computeForPassword("asdf".getBytes()));
dpms.mUserPasswordMetrics.put(
parentUser.id,
- PasswordMetrics.computeForPassword("parentUser"));
+ PasswordMetrics.computeForPassword("parentUser".getBytes()));
assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
}
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 d2caa0af0ba2..94d21ddeaa2b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
@@ -18,24 +18,22 @@ 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.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.os.RemoteException;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
-import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
-
-import java.util.ArrayList;
import org.mockito.ArgumentCaptor;
+import java.util.ArrayList;
+
/**
* Run the synthetic password tests with caching enabled.
*
@@ -56,10 +54,10 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
}
public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
@@ -67,45 +65,46 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
}
public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
- final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password";
- final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword";
+ final byte[] password =
+ "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
+ final byte[] newPassword =
+ "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, 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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
// Ensure the same secret was passed each time
ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
@@ -114,27 +113,29 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
}
public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
- final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password";
- final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword";
+ final byte[] password =
+ "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
+ final byte[] newPassword =
+ "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
// Disable caching for this test
enableSpCaching(false);
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
assertExpectException(IllegalStateException.class, /* messageRegex= */ null,
- () -> mService.setLockCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
+ () -> mService.setLockCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
}
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 bf71318cf50a..f4632db3cb6d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -133,12 +133,12 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
- protected void tieProfileLockToParent(int userId, String password) {
- mStorage.writeChildProfileLock(userId, password.getBytes());
+ protected void tieProfileLockToParent(int userId, byte[] password) {
+ mStorage.writeChildProfileLock(userId, password);
}
@Override
- protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
+ protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
KeyPermanentlyInvalidatedException {
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
@@ -151,7 +151,7 @@ public class LockSettingsServiceTestable extends LockSettingsService {
} catch (RemoteException e) {
// shouldn't happen.
}
- return new String(storedData);
+ return storedData;
}
}
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 5124803ee298..6e0ba3cb366c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -84,8 +84,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
try {
- mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
+ "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("Did not fail when enrolling using incorrect credential");
} catch (RemoteException expected) {
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
@@ -96,7 +96,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
public void testClearPasswordPrimaryUser() throws RemoteException {
final String PASSWORD = "password";
initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
- mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD,
+ mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertFalse(mService.havePassword(PRIMARY_USER_ID));
assertFalse(mService.havePattern(PRIMARY_USER_ID));
@@ -106,7 +106,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
public void testManagedProfileUnifiedChallenge() throws RemoteException {
final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
- mService.setLockCredential(firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.setLockCredential(firstUnifiedPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
@@ -125,8 +126,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
// verify credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ PRIMARY_USER_ID).getResponseCode());
// Verify that we have a new auth token for the profile
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
@@ -141,15 +142,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
*/
mStorageManager.setIgnoreBadUnlock(true);
// Change primary password and verify that profile SID remains
- mService.setLockCredential(secondUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- firstUnifiedPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential(secondUnifiedPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
// Clear unified challenge
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- secondUnifiedPassword, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
@@ -158,14 +160,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
public void testManagedProfileSeparateChallenge() throws RemoteException {
final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
final String profilePassword = "testManagedProfileSeparateChallenge-profile";
- mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(primaryPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
/* 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);
- mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(profilePassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
@@ -179,31 +183,32 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
// verify primary credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ PRIMARY_USER_ID).getResponseCode());
assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
// verify profile credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 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);
- mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- primaryPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
MANAGED_PROFILE_USER_ID).getResponseCode());
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
}
private void testCreateCredential(int userId, String credential, int type, int quality)
throws RemoteException {
- mService.setLockCredential(credential, type, null, quality, userId);
+ mService.setLockCredential(credential.getBytes(), type, null, quality,
+ userId);
assertVerifyCredentials(userId, credential, type, -1);
}
@@ -212,7 +217,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
mHasSecureLockScreen = false;
try {
- mService.setLockCredential(credential, type, null, quality, userId);
+ mService.setLockCredential(credential.getBytes(), type, null, quality,
+ userId);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
// Success - the exception was expected.
@@ -226,15 +232,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
String oldCredential, int oldType, int quality) throws RemoteException {
final long sid = 1234;
initializeStorageWithCredential(userId, oldCredential, oldType, sid);
- mService.setLockCredential(newCredential, newType, oldCredential, quality, userId);
+ mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
+ quality, userId);
assertVerifyCredentials(userId, newCredential, newType, sid);
}
private void assertVerifyCredentials(int userId, String credential, int type, long sid)
throws RemoteException{
final long challenge = 54321;
- VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
- userId);
+ VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
+ type, challenge, userId);
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
@@ -253,18 +260,19 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
// check for bad type
- assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
- incorrectType, challenge, userId).getResponseCode());
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
+ credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
// check for bad credential
- assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
- type, challenge, userId).getResponseCode());
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
+ ("0" + credential).getBytes(), type, 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();
if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
- mService.initializeSyntheticPasswordLocked(oldHash, credential, type,
+ mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
: PASSWORD_QUALITY_SOMETHING, 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 929c3b525db9..fcfc6d2267c5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -85,23 +85,24 @@ public class LockSettingsShellCommandTest {
public void testWrongPassword() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(false);
assertEquals(-1, mCommand.exec(mBinder, in, out, err,
new String[] { "set-pin", "--old", "1234" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt());
+ verify(mLockPatternUtils, never()).saveLockPassword(any(byte[].class), any(byte[].class),
+ anyInt(), anyInt());
}
@Test
public void testChangePin() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-pin", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC,
- mUserId);
+ verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
+ PASSWORD_QUALITY_NUMERIC, mUserId);
}
@Test
@@ -118,12 +119,12 @@ public class LockSettingsShellCommandTest {
public void testChangePassword() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-password", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC,
- mUserId);
+ verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
+ PASSWORD_QUALITY_ALPHABETIC, mUserId);
}
@Test
@@ -144,7 +145,8 @@ public class LockSettingsShellCommandTest {
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-pattern", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId);
+ verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234".getBytes(),
+ mUserId);
}
@Test
@@ -165,6 +167,6 @@ public class LockSettingsShellCommandTest {
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "clear", "--old", "1234" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).clearLock("1234", mUserId);
+ verify(mLockPatternUtils).clearLock("1234".getBytes(), mUserId);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
index 6f681797b88a..b9cb730caae1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
@@ -93,9 +93,13 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager {
}
@Override
- protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
+ protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
try {
- PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8);
+ char[] passwordChars = new char[password.length];
+ for (int i = 0; i < password.length; i++) {
+ passwordChars[i] = (char) password[i];
+ }
+ PBEKeySpec spec = new PBEKeySpec(passwordChars, salt, 10, outLen * 8);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return f.generateSecret(spec).getEncoded();
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
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 89e155ef0d8c..e6e020dbdb97 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -65,22 +65,23 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testPasswordBasedSyntheticPassword() throws RemoteException {
final int USER_ID = 10;
- final String PASSWORD = "user-password";
- final String BADPASSWORD = "bad-password";
+ final byte[] password = "user-password".getBytes();
+ final byte[] badPassword = "bad-password".getBytes();
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
mGateKeeperService, mUserManager);
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);
+ long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken,
+ PASSWORD_QUALITY_ALPHABETIC, USER_ID);
AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
- mGateKeeperService, handle, PASSWORD, USER_ID, null);
- assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword());
+ mGateKeeperService, handle, password, USER_ID, null);
+ assertArrayEquals(result.authToken.deriveKeyStorePassword(),
+ authToken.deriveKeyStorePassword());
result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle,
- BADPASSWORD, USER_ID, null);
+ badPassword, USER_ID, null);
assertNull(result.authToken);
}
@@ -97,30 +98,30 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testPasswordMigration() throws RemoteException {
- final String PASSWORD = "testPasswordMigration-password";
+ final byte[] password = "testPasswordMigration-password".getBytes();
disableSyntheticPassword();
- mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
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, LockPatternUtils.CREDENTIAL_TYPE_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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayNotEquals(primaryStorageKey,
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
- protected void initializeCredentialUnderSP(String password, int userId) throws RemoteException {
+ protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
enableSyntheticPassword();
int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
: PASSWORD_QUALITY_UNSPECIFIED;
@@ -130,62 +131,64 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordChangeCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordChangeCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordVerifyCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordVerifyCredential-password";
- final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword";
+ final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes();
+ final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
- BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
}
public void testSyntheticPasswordClearCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password";
- final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new";
+ final byte[] password =
+ "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes();
+ final byte[] badPassword =
+ "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+ mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Check the same secret was passed each time
@@ -195,24 +198,25 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password";
- final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new";
+ final byte[] password =
+ "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes();
+ final byte[] newPassword =
+ "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ 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,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
}
public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
- final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password";
- final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new";
+ final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes();
- initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID);
+ initializeCredentialUnderSP(password, SECONDARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
@@ -228,8 +232,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
- final String PASSWORD = "passwordForASyntheticPassword";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "passwordForASyntheticPassword".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
reset(mAuthSecretService);
mService.onUnlockUser(PRIMARY_USER_ID);
@@ -238,9 +242,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
- final String PASSWORD = "getASyntheticPassword";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
+ final byte[] password = "getASyntheticPassword".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
reset(mAuthSecretService);
@@ -250,7 +254,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
- final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
+ final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
disableSyntheticPassword();
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
@@ -284,8 +288,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
- final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary";
- final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile";
+ final byte[] primaryPassword =
+ "testManagedProfileSeparateChallengeMigration-primary".getBytes();
+ final byte[] profilePassword =
+ "testManagedProfileSeparateChallengeMigration-profile".getBytes();
disableSyntheticPassword();
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
@@ -326,92 +332,92 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testTokenBasedResetPassword() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
// Verify DPM gets notified about new device lock
mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
- PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN);
+ PasswordMetrics metric = PasswordMetrics.computeForPassword(pattern);
metric.quality = PASSWORD_QUALITY_SOMETHING;
verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedClearPassword() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
- mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String NEWPASSWORD = "password";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] newPassword = "password".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
- mLocalService.setLockCredentialWithToken(NEWPASSWORD,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
+ mLocalService.setLockCredentialWithToken(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 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 String token = "some-high-entropy-secure-token";
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -419,9 +425,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()
throws RemoteException {
- final String TOKEN = "some-high-entropy-secure-token";
+ final String token = "some-high-entropy-secure-token";
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -429,38 +435,38 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
throws RemoteException {
- final String TOKEN = "some-high-entropy-secure-token";
- final String PASSWORD = "password";
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ final byte[] password = "password".getBytes();
// Set up pre-SP user password
disableSyntheticPassword();
- mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
// Token not activated immediately since user password exists
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, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify token is activated
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
- final String password = "password";
- final String pattern = "123654";
- final String token = "some-high-entropy-secure-token";
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
mHasSecureLockScreen = false;
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
try {
mLocalService.setLockCredentialWithToken(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
@@ -470,7 +476,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
try {
mLocalService.setLockCredentialWithToken(pattern,
- LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
@@ -480,14 +486,14 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testgetHashFactorPrimaryUser() throws RemoteException {
- final String password = "password";
+ final byte[] password = "password".getBytes();
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
assertNotNull(hashFactor);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
assertNotNull(newHashFactor);
// Hash factor should never change after password change/removal
@@ -495,16 +501,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
}
public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
- final String pattern = "1236";
- mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
- PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ final byte[] pattern = "1236".getBytes();
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
}
public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
- final String primaryPassword = "primary";
- final String profilePassword = "profile";
+ final byte[] primaryPassword = "primary".getBytes();
+ final byte[] profilePassword = "profile".getBytes();
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
@@ -557,7 +563,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
public void testGsiDisablesAuthSecret() throws RemoteException {
mGsiService.setIsGsiRunning(true);
- final String password = "testGsiDisablesAuthSecret-password";
+ final byte[] password = "testGsiDisablesAuthSecret-password".getBytes();
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
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 c2d4846b14c0..a992dd126f5d 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
@@ -139,7 +139,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
TEST_CREDENTIAL_TYPE,
- TEST_CREDENTIAL,
+ TEST_CREDENTIAL.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -163,17 +163,17 @@ public class KeySyncTaskTest {
@Test
public void isPin_isTrueForNumericString() {
- assertTrue(KeySyncTask.isPin("3298432574398654376547"));
+ assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes()));
}
@Test
public void isPin_isFalseForStringContainingLetters() {
- assertFalse(KeySyncTask.isPin("398i54369548654"));
+ assertFalse(KeySyncTask.isPin("398i54369548654".getBytes()));
}
@Test
public void isPin_isFalseForStringContainingSymbols() {
- assertFalse(KeySyncTask.isPin("-3987543643"));
+ assertFalse(KeySyncTask.isPin("-3987543643".getBytes()));
}
@Test
@@ -182,8 +182,8 @@ public class KeySyncTaskTest {
byte[] salt = randomBytes(16);
assertArrayEquals(
- KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials),
- KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials));
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()));
}
@Test
@@ -192,8 +192,8 @@ public class KeySyncTaskTest {
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"),
- KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345")));
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234".getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345".getBytes())));
}
@Test
@@ -202,34 +202,38 @@ public class KeySyncTaskTest {
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials),
- KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials)));
+ KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
+ credentials.getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
+ credentials.getBytes())));
}
@Test
public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() {
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"),
- KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567")));
+ KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"),
+ "4567".getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"),
+ "567".getBytes())));
}
@Test
public void getUiFormat_returnsPinIfPin() {
assertEquals(UI_FORMAT_PIN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes()));
}
@Test
public void getUiFormat_returnsPasswordIfPassword() {
assertEquals(UI_FORMAT_PASSWORD,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes()));
}
@Test
public void getUiFormat_returnsPatternIfPattern() {
assertEquals(UI_FORMAT_PATTERN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes()));
}
@@ -291,7 +295,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ password,
+ /*credential=*/ password.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -332,7 +336,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PATTERN,
- /*credential=*/ pattern,
+ /*credential=*/ pattern.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -366,7 +370,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ shortPassword,
+ /*credential=*/ shortPassword.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -526,7 +530,7 @@ public class KeySyncTaskTest {
verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256(
keyDerivationParams.getSalt(),
- TEST_CREDENTIAL);
+ TEST_CREDENTIAL.getBytes());
Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
assertThat(counterId).isNotNull();
byte[] recoveryKey = decryptThmEncryptedKey(
@@ -649,7 +653,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- password,
+ password.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -680,7 +684,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ pin,
+ /*credential=*/ pin.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -712,7 +716,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PATTERN,
- "12345",
+ "12345".getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -796,7 +800,7 @@ public class KeySyncTaskTest {
mSnapshotListenersStorage,
TEST_USER_ID,
/*credentialType=*/ 3,
- "12345",
+ "12345".getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
index 9b4c3beac582..6921bb27ceb2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -27,30 +27,30 @@ public class TestOnlyInsecureCertificateHelperTest {
@Test
public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse();
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345".getBytes())).isFalse();
assertThat(mHelper.doesCredentialSupportInsecureMode(
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse();
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())).isFalse();
}
@Test
public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isTrue();
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue();
+ (TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12").getBytes())).isTrue();
}
@Test
public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_NONE,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index a1db3e8d8ded..1319bad7a5ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -406,7 +406,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
}
@Test
- public void testFixedScreenConfigurationWhenMovingToDisplay() {
+ public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
// Initialize different bounds on a new display.
final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
newDisplay.setBounds(0, 0, 1000, 2000);
@@ -431,7 +431,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
}
@Test
- public void testFixedScreenBoundsWhenDisplaySizeChanged() {
+ public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
@@ -446,4 +446,28 @@ public class ActivityRecordTests extends ActivityTestsBase {
assertEquals(originalBounds, mActivity.getBounds());
}
+
+ @Test
+ public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
+ final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
+ | Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ mTask.getConfiguration().screenLayout = fixedScreenLayout
+ | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
+ mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.maxAspectRatio = 1.5f;
+ ensureActivityConfiguration();
+
+ // The initial configuration should inherit from parent.
+ assertEquals(mTask.getConfiguration().screenLayout,
+ mActivity.getConfiguration().screenLayout);
+
+ mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
+ | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+
+ // The size and aspect ratio bits don't change, but the layout direction should be updated.
+ assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
+ mActivity.getConfiguration().screenLayout);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index e007c8651454..a98a6046890d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -29,7 +29,6 @@ import static org.mockito.ArgumentMatchers.eq;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
@@ -49,7 +48,6 @@ import org.mockito.MockitoAnnotations;
*/
@SmallTest
@Presubmit
-@FlakyTest(bugId = 124357362)
public class AppWindowTokenAnimationTests extends WindowTestsBase {
private TestAppWindowToken mToken;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 69f7ced5d90c..b26aa050870a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -68,7 +68,6 @@ import android.view.Surface;
import android.view.ViewRootImpl;
import android.view.test.InsetsModeSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -97,7 +96,6 @@ import java.util.List;
public class DisplayContentTests extends WindowTestsBase {
@Test
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testForAllWindows() {
final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
mDisplayContent, "exiting app");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 3e025f6f36b5..fc1eb1c57198 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -30,7 +30,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -96,6 +95,7 @@ public class RecentTasksTest extends ActivityTestsBase {
private TestActivityTaskManagerService mTestService;
private ActivityDisplay mDisplay;
private ActivityDisplay mOtherDisplay;
+ private ActivityDisplay mSingleTaskDisplay;
private ActivityStack mStack;
private ActivityStack mHomeStack;
private TestTaskPersister mTaskPersister;
@@ -547,6 +547,41 @@ public class RecentTasksTest extends ActivityTestsBase {
assertTrimmed(mTasks.get(0), mTasks.get(1));
}
+ /**
+ * Tests that tasks on singleTaskDisplay are not visible and not trimmed/removed.
+ */
+ @Test
+ public void testVisibleTasks_singleTaskDisplay() {
+ mRecentTasks.setOnlyTestVisibleRange();
+ mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
+
+ ActivityStack singleTaskStack = mSingleTaskDisplay.createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+ TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+ .setStack(singleTaskStack)
+ .build();
+
+ assertFalse("Tasks on singleTaskDisplay should not be visible recents",
+ mRecentTasks.isVisibleRecentTask(excludedTask1));
+
+ mRecentTasks.add(excludedTask1);
+
+ // Add N+1 visible tasks.
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ mRecentTasks.add(mTasks.get(2));
+ mRecentTasks.add(mTasks.get(3));
+
+ // excludedTask is not trimmed.
+ assertTrimmed(mTasks.get(0));
+
+ mRecentTasks.removeAllVisibleTasks();
+
+ // Only visible tasks removed.
+ assertTrimmed(mTasks.get(0), mTasks.get(1), mTasks.get(2), mTasks.get(3));
+ }
+
@Test
public void testBackStackTasks_expectNoTrim() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
@@ -879,8 +914,12 @@ public class RecentTasksTest extends ActivityTestsBase {
super.createDefaultDisplay();
mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1);
+ mSingleTaskDisplay = TestActivityDisplay.create(mTestStackSupervisor,
+ DEFAULT_DISPLAY + 2);
+ mSingleTaskDisplay.setDisplayToSingleTaskInstance();
mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
+ mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index ace179acdeb5..cdbb12109c58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -29,13 +29,11 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo;
@@ -474,6 +472,22 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
}
@Test
+ public void testUsesFullscreenWhenRequestedOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
public void testUsesFreeformByDefaultForPostNApp() {
final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
WINDOWING_MODE_FREEFORM);
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 b1f942eb2261..70ed62a4a11e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -175,10 +175,14 @@ public class TaskStackTests extends WindowTestsBase {
@Test
public void testStackOutset() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
- spyOn(stack);
-
final int stackOutset = 10;
- doReturn(stackOutset).when(stack).getStackOutset();
+ // Clear the handler and hold the lock for mock, to prevent multi-thread issue.
+ waitUntilHandlersIdle();
+ synchronized (mWm.mGlobalLock) {
+ spyOn(stack);
+
+ doReturn(stackOutset).when(stack).getStackOutset();
+ }
final Rect stackBounds = new Rect(200, 200, 800, 1000);
// Update surface position and size by the given bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b0e20b89b811..b03f63b9159f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -110,8 +110,11 @@ public class WindowStateTests extends WindowTestsBase {
// TODO: Let the insets source with new mode keep the visibility control, and remove this
// setup code. Now mTopFullscreenOpaqueWindowState will take back the control of insets
// visibility.
- spyOn(mDisplayContent);
- doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded();
+ // Hold the lock to protect the mock from accesssing by other threads.
+ synchronized (mWm.mGlobalLock) {
+ spyOn(mDisplayContent);
+ doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded();
+ }
}
@Test
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index e6182eda852a..740b970b8e7c 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -119,7 +119,7 @@ public abstract class CellSignalStrength {
/** @hide */
protected static final int getAsuFromRssiDbm(int dbm) {
if (dbm == CellInfo.UNAVAILABLE) return 99;
- return (dbm / 2) + 113;
+ return (dbm + 113) / 2;
}
// Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
index d6a8065feabe..c3387f3f112d 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
@@ -1,5 +1,7 @@
package android.telephony;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -10,14 +12,17 @@ import java.util.Objects;
* Class that stores information specific to data network registration.
* @hide
*/
-public class DataSpecificRegistrationStates implements Parcelable{
+@SystemApi
+public final class DataSpecificRegistrationStates implements Parcelable{
/**
+ * @hide
* The maximum number of simultaneous Data Calls that
* must be established using setupDataCall().
*/
public final int maxDataCalls;
/**
+ * @hide
* Indicates if the use of dual connectivity with NR is restricted.
* Reference: 3GPP TS 24.301 v15.03 section 9.3.3.12A.
*/
@@ -25,7 +30,7 @@ public class DataSpecificRegistrationStates implements Parcelable{
/**
* Indicates if NR is supported by the selected PLMN.
- *
+ * @hide
* {@code true} if the bit N is in the PLMN-InfoList-r15 is true and the selected PLMN is
* present in plmn-IdentityList at position N.
* Reference: 3GPP TS 36.331 v15.2.2 section 6.3.1 PLMN-InfoList-r15.
@@ -34,6 +39,7 @@ public class DataSpecificRegistrationStates implements Parcelable{
public final boolean isNrAvailable;
/**
+ * @hide
* Indicates that if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving
* cell.
*
@@ -47,8 +53,11 @@ public class DataSpecificRegistrationStates implements Parcelable{
/**
* Provides network support info for LTE VoPS and LTE Emergency bearer support
*/
- public final LteVopsSupportInfo lteVopsSupportInfo;
+ private final LteVopsSupportInfo lteVopsSupportInfo;
+ /**
+ * @hide
+ */
DataSpecificRegistrationStates(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
@@ -126,4 +135,12 @@ public class DataSpecificRegistrationStates implements Parcelable{
return new DataSpecificRegistrationStates[size];
}
};
+
+ /**
+ * @return LteVopsSupportInfo
+ */
+ @NonNull
+ public LteVopsSupportInfo getLteVopsSupportInfo() {
+ return lteVopsSupportInfo;
+ }
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index 6e6d59e62148..84d6628d47d2 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -349,7 +349,7 @@ public class NetworkRegistrationState implements Parcelable {
}
/**
- * @hide
+ * @return Data registration related info
*/
@Nullable
public DataSpecificRegistrationStates getDataSpecificStates() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c1d14406dc40..d39c5f8892c8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1366,6 +1366,26 @@ public class TelephonyManager {
* Intent sent when an error occurs that debug tools should log and possibly take further
* action such as capturing vendor-specific logs.
*
+ * A privileged application that reads these events should take appropriate vendor-specific
+ * action to record the event and collect further information to assist in analysis, debugging,
+ * and resolution of any associated issue.
+ *
+ * <p>This event should not be used for generic logging or diagnostic monitoring purposes and
+ * should generally be sent at a low rate. Instead, this mechanism should be used for the
+ * framework to notify a debugging application that an event (such as a bug) has occured
+ * within the framework if that event should trigger the collection and preservation of other
+ * more detailed device state for debugging.
+ *
+ * <p>At most one application can receive these events and should register a receiver in
+ * in the application manifest. For performance reasons, if no application to receive these
+ * events is detected at boot, then these events will not be sent.
+ *
+ * <p>Each event will include an {@link EXTRA_DEBUG_EVENT_ID} that will uniquely identify the
+ * event that has occurred. Each event will be sent to the diagnostic monitor only once per
+ * boot cycle (as another optimization).
+ *
+ * @see #EXTRA_DEBUG_EVENT_ID
+ * @see #EXTRA_DEBUG_EVENT_DESCRIPTION
* @hide
*/
@SystemApi
@@ -1373,21 +1393,23 @@ public class TelephonyManager {
public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
/**
- * An arbitrary ParcelUuid which should be consistent for each occurrence of the same event.
+ * An arbitrary ParcelUuid which should be consistent for each occurrence of a DebugEvent.
*
- * This field must be included in all events.
+ * This field must be included in all {@link ACTION_DEBUG_EVENT} events.
*
+ * @see #ACTION_DEBUG_EVENT
* @hide
*/
@SystemApi
public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
/**
- * A freeform string description of the event.
+ * A freeform string description of the DebugEvent.
*
- * This field is optional for all events and as a guideline should not exceed 80 characters
- * and should be as short as possible to convey the essence of the event.
+ * This field is optional for all {@link ACTION_DEBUG_EVENT}s, as a guideline should not
+ * exceed 80 characters, and should be as short as possible to convey the essence of the event.
*
+ * @see #ACTION_DEBUG_EVENT
* @hide
*/
@SystemApi
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 19f357a14687..0192ffbe263c 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -30,6 +30,7 @@ public final class UiccCardInfo implements Parcelable {
private final String mEid;
private final String mIccId;
private final int mSlotIndex;
+ private final boolean mIsRemovable;
public static final Creator<UiccCardInfo> CREATOR = new Creator<UiccCardInfo>() {
@Override
@@ -49,6 +50,7 @@ public final class UiccCardInfo implements Parcelable {
mEid = in.readString();
mIccId = in.readString();
mSlotIndex = in.readInt();
+ mIsRemovable = in.readByte() != 0;
}
@Override
@@ -58,6 +60,7 @@ public final class UiccCardInfo implements Parcelable {
dest.writeString(mEid);
dest.writeString(mIccId);
dest.writeInt(mSlotIndex);
+ dest.writeByte((byte) (mIsRemovable ? 1 : 0));
}
@Override
@@ -65,16 +68,21 @@ public final class UiccCardInfo implements Parcelable {
return 0;
}
- public UiccCardInfo(boolean isEuicc, int cardId, String eid, String iccId, int slotIndex) {
+ /**
+ * @hide
+ */
+ public UiccCardInfo(boolean isEuicc, int cardId, String eid, String iccId, int slotIndex,
+ boolean isRemovable) {
this.mIsEuicc = isEuicc;
this.mCardId = cardId;
this.mEid = eid;
this.mIccId = iccId;
this.mSlotIndex = slotIndex;
+ this.mIsRemovable = isRemovable;
}
/**
- * Return whether the UiccCardInfo is an eUICC.
+ * Return whether the UICC is an eUICC.
* @return true if the UICC is an eUICC.
*/
public boolean isEuicc() {
@@ -127,7 +135,17 @@ public final class UiccCardInfo implements Parcelable {
* @hide
*/
public UiccCardInfo getUnprivileged() {
- return new UiccCardInfo(mIsEuicc, mCardId, null, null, mSlotIndex);
+ return new UiccCardInfo(mIsEuicc, mCardId, null, null, mSlotIndex, mIsRemovable);
+ }
+
+ /**
+ * Return whether the UICC or eUICC is removable.
+ * <p>
+ * UICCs are generally removable, but eUICCs may be removable or built in to the device.
+ * @return true if the UICC or eUICC is removable
+ */
+ public boolean isRemovable() {
+ return mIsRemovable;
}
@Override
@@ -144,12 +162,13 @@ public final class UiccCardInfo implements Parcelable {
&& (mCardId == that.mCardId)
&& (Objects.equals(mEid, that.mEid))
&& (Objects.equals(mIccId, that.mIccId))
- && (mSlotIndex == that.mSlotIndex));
+ && (mSlotIndex == that.mSlotIndex)
+ && (mIsRemovable == that.mIsRemovable));
}
@Override
public int hashCode() {
- return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mSlotIndex);
+ return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mSlotIndex, mIsRemovable);
}
@Override
@@ -164,6 +183,8 @@ public final class UiccCardInfo implements Parcelable {
+ mIccId
+ ", mSlotIndex="
+ mSlotIndex
+ + ", mIsRemovable="
+ + mIsRemovable
+ ")";
}
}
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index a39992b17f8e..93a7da04c56e 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -15,15 +15,15 @@
*/
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
-import android.annotation.IntDef;
-
/**
* Class for the information of a UICC slot.
* @hide
@@ -61,6 +61,7 @@ public class UiccSlotInfo implements Parcelable {
private final @CardStateInfo int mCardStateInfo;
private final int mLogicalSlotIdx;
private final boolean mIsExtendedApduSupported;
+ private final boolean mIsRemovable;
public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
@Override
@@ -81,6 +82,7 @@ public class UiccSlotInfo implements Parcelable {
mCardStateInfo = in.readInt();
mLogicalSlotIdx = in.readInt();
mIsExtendedApduSupported = in.readByte() != 0;
+ mIsRemovable = in.readByte() != 0;
}
@Override
@@ -91,6 +93,7 @@ public class UiccSlotInfo implements Parcelable {
dest.writeInt(mCardStateInfo);
dest.writeInt(mLogicalSlotIdx);
dest.writeByte((byte) (mIsExtendedApduSupported ? 1 : 0));
+ dest.writeByte((byte) (mIsRemovable ? 1 : 0));
}
@Override
@@ -98,6 +101,11 @@ public class UiccSlotInfo implements Parcelable {
return 0;
}
+ /**
+ * Construct a UiccSlotInfo.
+ * @deprecated apps should not be constructing UiccSlotInfo objects
+ */
+ @Deprecated
public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
@CardStateInfo int cardStateInfo, int logicalSlotIdx, boolean isExtendedApduSupported) {
this.mIsActive = isActive;
@@ -106,6 +114,22 @@ public class UiccSlotInfo implements Parcelable {
this.mCardStateInfo = cardStateInfo;
this.mLogicalSlotIdx = logicalSlotIdx;
this.mIsExtendedApduSupported = isExtendedApduSupported;
+ this.mIsRemovable = false;
+ }
+
+ /**
+ * @hide
+ */
+ public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
+ @CardStateInfo int cardStateInfo, int logicalSlotIdx, boolean isExtendedApduSupported,
+ boolean isRemovable) {
+ this.mIsActive = isActive;
+ this.mIsEuicc = isEuicc;
+ this.mCardId = cardId;
+ this.mCardStateInfo = cardStateInfo;
+ this.mLogicalSlotIdx = logicalSlotIdx;
+ this.mIsExtendedApduSupported = isExtendedApduSupported;
+ this.mIsRemovable = isRemovable;
}
public boolean getIsActive() {
@@ -136,6 +160,16 @@ public class UiccSlotInfo implements Parcelable {
return mIsExtendedApduSupported;
}
+ /**
+ * Return whether the UICC slot is for a removable UICC.
+ * <p>
+ * UICCs are generally removable, but eUICCs may be removable or built in to the device.
+ * @return true if the slot is for removable UICCs
+ */
+ public boolean isRemovable() {
+ return mIsRemovable;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -151,7 +185,8 @@ public class UiccSlotInfo implements Parcelable {
&& (Objects.equals(mCardId, that.mCardId))
&& (mCardStateInfo == that.mCardStateInfo)
&& (mLogicalSlotIdx == that.mLogicalSlotIdx)
- && (mIsExtendedApduSupported == that.mIsExtendedApduSupported);
+ && (mIsExtendedApduSupported == that.mIsExtendedApduSupported)
+ && (mIsRemovable == that.mIsRemovable);
}
@Override
@@ -163,6 +198,7 @@ public class UiccSlotInfo implements Parcelable {
result = 31 * result + mCardStateInfo;
result = 31 * result + mLogicalSlotIdx;
result = 31 * result + (mIsExtendedApduSupported ? 1 : 0);
+ result = 31 * result + (mIsRemovable ? 1 : 0);
return result;
}
@@ -180,6 +216,8 @@ public class UiccSlotInfo implements Parcelable {
+ mLogicalSlotIdx
+ ", mIsExtendedApduSupported="
+ mIsExtendedApduSupported
+ + ", mIsRemovable="
+ + mIsRemovable
+ ")";
}
}
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 837ef54a2f24..d11a0de24fb5 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -99,7 +99,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
public int mRttMode;
// RTT Audio Speech Indicator
/** @hide */
- public boolean mHasRttAudioSpeech = false;
+ public boolean mIsReceivingRttAudio = false;
/** @hide */
public ImsStreamMediaProfile(Parcel in) {
@@ -201,7 +201,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
", videoQuality=" + mVideoQuality +
", videoDirection=" + mVideoDirection +
", rttMode=" + mRttMode +
- ", hasRttAudioSpeech=" + mHasRttAudioSpeech + " }";
+ ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
}
@Override
@@ -216,7 +216,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
out.writeInt(mVideoQuality);
out.writeInt(mVideoDirection);
out.writeInt(mRttMode);
- out.writeBoolean(mHasRttAudioSpeech);
+ out.writeBoolean(mIsReceivingRttAudio);
}
private void readFromParcel(Parcel in) {
@@ -225,7 +225,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
mVideoQuality = in.readInt();
mVideoDirection = in.readInt();
mRttMode = in.readInt();
- mHasRttAudioSpeech = in.readBoolean();
+ mIsReceivingRttAudio = in.readBoolean();
}
public static final Creator<ImsStreamMediaProfile> CREATOR =
@@ -256,8 +256,12 @@ public final class ImsStreamMediaProfile implements Parcelable {
mRttMode = rttMode;
}
- public void setRttAudioSpeech(boolean audioOn) {
- mHasRttAudioSpeech = audioOn;
+ /**
+ * Sets whether the remote party is transmitting audio over the RTT call.
+ * @param audioOn true if audio is being received, false otherwise.
+ */
+ public void setReceivingRttAudio(boolean audioOn) {
+ mIsReceivingRttAudio = audioOn;
}
public int getAudioQuality() {
@@ -280,7 +284,10 @@ public final class ImsStreamMediaProfile implements Parcelable {
return mRttMode;
}
- public boolean getRttAudioSpeech() {
- return mHasRttAudioSpeech;
+ /**
+ * @return true if remote party is transmitting audio, false otherwise.
+ */
+ public boolean isReceivingRttAudio() {
+ return mIsReceivingRttAudio;
}
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index a922ab601442..6de608e7b53b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -84,6 +84,6 @@ interface ITelephonyRegistry {
void notifyActiveDataSubIdChanged(int activeDataSubId);
void notifyRadioPowerStateChanged(in int state);
void notifyEmergencyNumberList();
- void notifyCallQualityChanged(in CallQuality callQuality, int phoneId);
+ void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int callNetworkType);
void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo);
}
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 157609cec09c..8aa0aaf363dd 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -44,7 +44,7 @@ java_sdk_library {
// ==========================================
// This is only intended for inclusion in the android.test.runner-minus-junit,
// robolectric_android-all-stub and repackaged.android.test.* libraries.
-// Must not be used elewhere.
+// Must not be used elsewhere.
java_library_static {
name: "android.test.base_static",
installable: false,
@@ -61,19 +61,6 @@ java_library_static {
sdk_version: "current",
}
-// Build the legacy-test library
-// =============================
-// This contains the junit.framework and android.test classes that were in
-// Android API level 25 excluding those from android.test.runner.
-// Also contains the com.android.internal.util.Predicate[s] classes.
-java_library {
- name: "legacy-test",
- installable: true,
-
- sdk_version: "current",
- static_libs: ["android.test.base_static"],
-}
-
// Build the repackaged.android.test.base library
// ==============================================
// This contains repackaged versions of the classes from
@@ -93,8 +80,8 @@ java_library_static {
// ===============================================
// This contains the android.test classes from android.test.base plus
// the com.android.internal.util.Predicate[s] classes. This is only
-// intended for inclusion in the android.test.legacy and
-// legacy-android-test static libraries and must not be used elsewhere.
+// intended for inclusion in android.test.legacy and must not be used
+// elsewhere.
java_library_static {
name: "android.test.base-minus-junit",
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
deleted file mode 100644
index a69f422b3bdb..000000000000
--- a/test-legacy/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// Build the legacy-android-test library
-// =====================================
-// This contains the android.test classes that were in Android API level 25,
-// including those from android.test.runner.
-// Also contains the com.android.internal.util.Predicate[s] classes.
-java_library_static {
- name: "legacy-android-test",
-
- static_libs: [
- "android.test.base-minus-junit",
- "android.test.runner-minus-junit",
- "android.test.mock_static",
- ],
-
- no_framework_libs: true,
- libs: [
- "framework",
- "junit",
- ],
-}
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index da47de0a3d35..af26c5b80717 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -24,35 +24,16 @@ ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
# Built against the SDK so that it can be statically included in APKs
# without breaking link type checks.
#
-# This builds directly from the source rather than simply statically
-# including the android.test.base-minus-junit and
-# android.test.runner-minus-junit libraries because the latter library
-# cannot itself be built against the SDK. That is because it uses on
-# an internal method (setTestContext) on the AndroidTestCase class.
-# That class is provided by both the android.test.base-minus-junit and
-# the current SDK and as the latter is first on the classpath its
-# version is used. Unfortunately, it does not provide the internal
-# method and so compilation fails.
-#
-# Building from source avoids that because the compiler will use the
-# source version of AndroidTestCase instead of the one from the current
-# SDK.
-#
-# The use of the internal method does not prevent this from being
-# statically included because the class that provides the method is
-# also included in this library.
include $(CLEAR_VARS)
LOCAL_MODULE := android.test.legacy
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, ../test-base/src/android) \
- $(call all-java-files-under, ../test-base/src/com) \
- $(call all-java-files-under, ../test-runner/src/android) \
-
LOCAL_SDK_VERSION := current
LOCAL_JAVA_LIBRARIES := junit android.test.mock.stubs
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.test.base-minus-junit \
+ android.test.runner-minus-junit \
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 43b765d8b783..e1d6e01d6d06 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,19 +30,3 @@ java_sdk_library {
srcs_lib_whitelist_pkgs: ["android"],
compile_dex: true,
}
-
-// Build the android.test.mock_static library
-// ==========================================
-// This is only intended for inclusion in the legacy-android-test.
-// Must not be used elewhere.
-java_library_static {
- name: "android.test.mock_static",
-
- java_version: "1.8",
- srcs: ["src/**/*.java"],
-
- no_framework_libs: true,
- libs: [
- "framework",
- ],
-}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index db5053eeb903..35212020be7b 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -45,7 +45,7 @@ java_sdk_library {
// Build the android.test.runner-minus-junit library
// =================================================
-// This is only intended for inclusion in the legacy-android-test static
+// This is only intended for inclusion in the android.test.legacy static
// library and must not be used elsewhere.
java_library {
name: "android.test.runner-minus-junit",
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 9e5d8cebf43a..db9376b844f9 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -21,6 +21,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/Av1.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v1
LOCAL_PACKAGE_NAME := RollbackTestAppAv1
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_AV1 := $(LOCAL_INSTALLED_MODULE)
@@ -32,6 +33,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/Av2.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v2
LOCAL_PACKAGE_NAME := RollbackTestAppAv2
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)
@@ -43,6 +45,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/ACrashingV2.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v2
LOCAL_PACKAGE_NAME := RollbackTestAppACrashingV2
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_A_CRASHING_V2 := $(LOCAL_INSTALLED_MODULE)
@@ -54,6 +57,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/Bv1.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v1
LOCAL_PACKAGE_NAME := RollbackTestAppBv1
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_BV1 := $(LOCAL_INSTALLED_MODULE)
@@ -65,10 +69,39 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
LOCAL_MANIFEST_FILE := TestApp/Bv2.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v2
LOCAL_PACKAGE_NAME := RollbackTestAppBv2
include $(BUILD_PACKAGE)
ROLLBACK_TEST_APP_BV2 := $(LOCAL_INSTALLED_MODULE)
+# RollbackTestAppASplitV1.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Av1.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v1
+LOCAL_PACKAGE_NAME := RollbackTestAppASplitV1
+LOCAL_PACKAGE_SPLITS := anydpi
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_A_SPLIT_V1 := $(LOCAL_INSTALLED_MODULE)
+ROLLBACK_TEST_APP_A_SPLIT_V1_SPLIT := $(installed_apk_splits)
+
+# RollbackTestAppASplitV2.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Av2.xml
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/TestApp/res_v2
+LOCAL_PACKAGE_NAME := RollbackTestAppASplitV2
+LOCAL_PACKAGE_SPLITS := anydpi
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_A_SPLIT_V2 := $(LOCAL_INSTALLED_MODULE)
+ROLLBACK_TEST_APP_A_SPLIT_V2_SPLIT := $(installed_apk_splits)
+
# RollbackTest
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, RollbackTest/src)
@@ -82,6 +115,10 @@ LOCAL_JAVA_RESOURCE_FILES := \
$(ROLLBACK_TEST_APP_A_CRASHING_V2) \
$(ROLLBACK_TEST_APP_BV1) \
$(ROLLBACK_TEST_APP_BV2) \
+ $(ROLLBACK_TEST_APP_A_SPLIT_V1) \
+ $(ROLLBACK_TEST_APP_A_SPLIT_V1_SPLIT) \
+ $(ROLLBACK_TEST_APP_A_SPLIT_V2) \
+ $(ROLLBACK_TEST_APP_A_SPLIT_V2_SPLIT) \
$(ROLLBACK_TEST_APEX_V1) \
$(ROLLBACK_TEST_APEX_V2)
LOCAL_MANIFEST_FILE := RollbackTest/AndroidManifest.xml
@@ -103,5 +140,9 @@ include $(BUILD_HOST_JAVA_LIBRARY)
ROLLBACK_TEST_APP_AV1 :=
ROLLBACK_TEST_APP_AV2 :=
ROLLBACK_TEST_APP_A_CRASHING_V2 :=
+ROLLBACK_TEST_APP_A_SPLIT_V1 :=
+ROLLBACK_TEST_APP_A_SPLIT_V1_SPLIT :=
+ROLLBACK_TEST_APP_A_SPLIT_V2 :=
+ROLLBACK_TEST_APP_A_SPLIT_V2_SPLIT :=
ROLLBACK_TEST_APP_BV1 :=
ROLLBACK_TEST_APP_BV2 :=
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index bd0881f18423..7be83edd91b9 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -32,6 +32,7 @@ import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
import android.os.HandlerThread;
+import android.provider.DeviceConfig;
import android.support.test.InstrumentationRegistry;
import android.util.Log;
@@ -331,6 +332,64 @@ public class RollbackTest {
}
/**
+ * Test the scheduling aspect of rollback expiration.
+ */
+ @Test
+ public void testRollbackExpiresAfterLifetime() throws Exception {
+ long expirationTime = TimeUnit.SECONDS.toMillis(30);
+ long defaultExpirationTime = TimeUnit.HOURS.toMillis(48);
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.WRITE_DEVICE_CONFIG);
+
+ DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
+ DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ Long.toString(expirationTime), false /* makeDefault*/);
+
+ // Pull the new expiration time from DeviceConfig
+ rm.reloadPersistedData();
+
+ // Uninstall TEST_APP_A
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // Install v1 of the app (without rollbacks enabled).
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // Upgrade from v1 to v2, with rollbacks enabled.
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // Check that the rollback data has not expired
+ Thread.sleep(1000);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+
+ // Give it a little more time, but still not the long enough to expire
+ Thread.sleep(expirationTime / 2);
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
+
+ // Check that the data has expired after the expiration time (with a buffer of 1 second)
+ Thread.sleep(expirationTime / 2);
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ } finally {
+ DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
+ DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ Long.toString(defaultExpirationTime), false /* makeDefault*/);
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
* Test explicit expiration of rollbacks.
* Does not test the scheduling aspects of rollback expiration.
*/
@@ -442,6 +501,39 @@ public class RollbackTest {
}
/**
+ * Test rollback of apks involving splits.
+ */
+ @Test
+ public void testRollbackWithSplits() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.installSplit(false,
+ "RollbackTestAppASplitV1.apk",
+ "RollbackTestAppASplitV1_anydpi.apk");
+ processUserData(TEST_APP_A);
+
+ RollbackTestUtils.installSplit(true,
+ "RollbackTestAppASplitV2.apk",
+ "RollbackTestAppASplitV2_anydpi.apk");
+ processUserData(TEST_APP_A);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertNotNull(rollback);
+ RollbackTestUtils.rollback(rollback.getRollbackId());
+ processUserData(TEST_APP_A);
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
* Test restrictions on rollback broadcast sender.
* A random app should not be able to send a ROLLBACK_COMMITTED broadcast.
*/
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index def5b8ead283..f28714c87125 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -130,6 +130,19 @@ class RollbackTestUtils {
*/
static void install(String resourceName, boolean enableRollback)
throws InterruptedException, IOException {
+ installSplit(enableRollback, resourceName);
+ }
+
+ /**
+ * Installs the apk with the given name and its splits.
+ *
+ * @param enableRollback if rollback should be enabled.
+ * @param resourceNames names of class loader resources for the apk and
+ * its splits to install.
+ * @throws AssertionError if the installation fails.
+ */
+ static void installSplit(boolean enableRollback, String... resourceNames)
+ throws InterruptedException, IOException {
Context context = InstrumentationRegistry.getContext();
PackageInstaller.Session session = null;
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
@@ -142,12 +155,14 @@ class RollbackTestUtils {
session = packageInstaller.openSession(sessionId);
ClassLoader loader = RollbackTest.class.getClassLoader();
- try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
- InputStream is = loader.getResourceAsStream(resourceName);) {
- byte[] buffer = new byte[4096];
- int n;
- while ((n = is.read(buffer)) >= 0) {
- packageInSession.write(buffer, 0, n);
+ for (String resourceName : resourceNames) {
+ try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
+ InputStream is = loader.getResourceAsStream(resourceName);) {
+ byte[] buffer = new byte[4096];
+ int n;
+ while ((n = is.read(buffer)) >= 0) {
+ packageInSession.write(buffer, 0, n);
+ }
}
}
diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml
index 5708d2385f01..77bfd4e0f9a0 100644
--- a/tests/RollbackTest/TestApp/ACrashingV2.xml
+++ b/tests/RollbackTest/TestApp/ACrashingV2.xml
@@ -23,7 +23,6 @@
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App A v2">
- <meta-data android:name="version" android:value="2" />
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml
index 996d831013a8..63729fbaaf28 100644
--- a/tests/RollbackTest/TestApp/Av1.xml
+++ b/tests/RollbackTest/TestApp/Av1.xml
@@ -23,7 +23,6 @@
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App A v1">
- <meta-data android:name="version" android:value="1" />
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.MainActivity">
diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml
index 21c7260b570b..f0e909feabf3 100644
--- a/tests/RollbackTest/TestApp/Av2.xml
+++ b/tests/RollbackTest/TestApp/Av2.xml
@@ -23,7 +23,6 @@
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App A v2">
- <meta-data android:name="version" android:value="2" />
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.MainActivity">
diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml
index de0fd0d6d616..ca9c2ec47a20 100644
--- a/tests/RollbackTest/TestApp/Bv1.xml
+++ b/tests/RollbackTest/TestApp/Bv1.xml
@@ -23,7 +23,6 @@
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App B v1">
- <meta-data android:name="version" android:value="1" />
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.MainActivity">
diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml
index 6c2e66a3220c..bd3e6133f6f6 100644
--- a/tests/RollbackTest/TestApp/Bv2.xml
+++ b/tests/RollbackTest/TestApp/Bv2.xml
@@ -23,7 +23,6 @@
<uses-sdk android:minSdkVersion="19" />
<application android:label="Rollback Test App B v2">
- <meta-data android:name="version" android:value="2" />
<receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
android:exported="true" />
<activity android:name="com.android.tests.rollback.testapp.MainActivity">
diff --git a/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
new file mode 100644
index 000000000000..90d3da2565cc
--- /dev/null
+++ b/tests/RollbackTest/TestApp/res_v1/values-anydpi/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <integer name="split_version">1</integer>
+</resources>
diff --git a/tests/RollbackTest/TestApp/res_v1/values/values.xml b/tests/RollbackTest/TestApp/res_v1/values/values.xml
new file mode 100644
index 000000000000..0447c74a79a6
--- /dev/null
+++ b/tests/RollbackTest/TestApp/res_v1/values/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <integer name="app_version">1</integer>
+ <integer name="split_version">0</integer>
+</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml b/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
new file mode 100644
index 000000000000..9a1aa7fd8461
--- /dev/null
+++ b/tests/RollbackTest/TestApp/res_v2/values-anydpi/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <integer name="split_version">2</integer>
+</resources>
diff --git a/tests/RollbackTest/TestApp/res_v2/values/values.xml b/tests/RollbackTest/TestApp/res_v2/values/values.xml
new file mode 100644
index 000000000000..fd988f597f61
--- /dev/null
+++ b/tests/RollbackTest/TestApp/res_v2/values/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <integer name="app_version">2</integer>
+ <integer name="split_version">0</integer>
+</resources>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
index fde6a83b6e56..38c658e795aa 100644
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
@@ -19,9 +19,7 @@ package com.android.tests.rollback.testapp;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
+import android.content.res.Resources;
import java.io.File;
import java.io.FileNotFoundException;
@@ -35,6 +33,8 @@ import java.util.Scanner;
*/
public class ProcessUserData extends BroadcastReceiver {
+ private static final String TAG = "RollbackTestApp";
+
/**
* Exception thrown in case of issue with user data.
*/
@@ -66,14 +66,19 @@ public class ProcessUserData extends BroadcastReceiver {
* @throws UserDataException in case of problems with app user data.
*/
public void processUserData(Context context) throws UserDataException {
- int appVersion = 0;
- try {
- ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
- context.getPackageName(), PackageManager.GET_META_DATA);
- Bundle bundle = appInfo.metaData;
- appVersion = bundle.getInt("version");
- } catch (PackageManager.NameNotFoundException e) {
- throw new UserDataException("Unable to get app version info", e);
+ Resources res = context.getResources();
+ String packageName = context.getPackageName();
+
+ int appVersionId = res.getIdentifier("app_version", "integer", packageName);
+ int appVersion = res.getInteger(appVersionId);
+
+ int splitVersionId = res.getIdentifier("split_version", "integer", packageName);
+ int splitVersion = res.getInteger(splitVersionId);
+
+ // Make sure the app version and split versions are compatible.
+ if (appVersion != splitVersion) {
+ throw new UserDataException("Split version " + splitVersion
+ + " does not match app version " + appVersion);
}
// Read the version of the app's user data and ensure it is compatible
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 0512bdc5bf72..bec6c6973613 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -769,7 +769,10 @@ int CompileCommand::Action(const std::vector<std::string>& args) {
auto collection = util::make_unique<io::FileCollection>();
// Collect data from the path for each input file.
- for (const std::string& arg : args) {
+ std::vector<std::string> sorted_args = args;
+ std::sort(sorted_args.begin(), sorted_args.end());
+
+ for (const std::string& arg : sorted_args) {
collection->InsertFile(arg);
}
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 51cc9032fb3e..e15f935cad27 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -79,6 +79,7 @@ std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiec
return nullptr;
}
+ std::vector<std::string> sorted_files;
while (struct dirent *entry = readdir(d.get())) {
std::string prefix_path = root.to_string();
file::AppendPath(&prefix_path, entry->d_name);
@@ -105,10 +106,15 @@ std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiec
continue;
}
- collection->InsertFile(full_path);
+ sorted_files.push_back(full_path);
}
}
+ std::sort(sorted_files.begin(), sorted_files.end());
+ for (const std::string& full_path : sorted_files) {
+ collection->InsertFile(full_path);
+ }
+
return collection;
}
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 59e89f515e82..4c02d94542d0 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -208,13 +208,14 @@ class Class():
class Package():
+ NAME = re.compile("package(?: .*)? ([A-Za-z.]+)")
+
def __init__(self, line, raw, blame):
self.line = line
self.raw = raw.strip(" {;")
self.blame = blame
- raw = raw.split()
- self.name = raw[raw.index("package")+1]
+ self.name = Package.NAME.match(raw).group(1)
self.name_path = self.name.split(".")
def __repr__(self):
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
index 3716bf9f5d6f..c10ef15d02ad 100644
--- a/tools/apilint/apilint_test.py
+++ b/tools/apilint/apilint_test.py
@@ -369,5 +369,21 @@ class V2ParserTests(unittest.TestCase):
m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);')
self.assertEquals('java.lang.String[]', m.typ)
+class PackageTests(unittest.TestCase):
+ def _package(self, raw):
+ return apilint.Package(123, raw, "blame")
+
+ def test_regular_package(self):
+ p = self._package("package an.pref.int {")
+ self.assertEquals('an.pref.int', p.name)
+
+ def test_annotation_package(self):
+ p = self._package("package @RestrictTo(a.b.C) an.pref.int {")
+ self.assertEquals('an.pref.int', p.name)
+
+ def test_multi_annotation_package(self):
+ p = self._package("package @Rt(a.b.L_G_P) @RestrictTo(a.b.C) an.pref.int {")
+ self.assertEquals('an.pref.int', p.name)
+
if __name__ == "__main__":
unittest.main()
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3881e9e68eca..4d6ff4816621 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -41,6 +42,8 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
@@ -339,6 +342,90 @@ public class WifiConfiguration implements Parcelable {
public static final String[] strings = { "current", "disabled", "enabled" };
}
+ /**
+ * Security types we support.
+ */
+ /** @hide */
+ public static final int SECURITY_TYPE_OPEN = 0;
+ /** @hide */
+ public static final int SECURITY_TYPE_WEP = 1;
+ /** @hide */
+ public static final int SECURITY_TYPE_PSK = 2;
+ /** @hide */
+ public static final int SECURITY_TYPE_EAP = 3;
+ /** @hide */
+ public static final int SECURITY_TYPE_SAE = 4;
+ /** @hide */
+ public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
+ /** @hide */
+ public static final int SECURITY_TYPE_OWE = 6;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_WEP,
+ SECURITY_TYPE_PSK,
+ SECURITY_TYPE_EAP,
+ SECURITY_TYPE_SAE,
+ SECURITY_TYPE_EAP_SUITE_B,
+ SECURITY_TYPE_OWE
+ })
+ public @interface SecurityType {}
+
+ /**
+ * @hide
+ * Set security params (sets the various bitsets exposed in WifiConfiguration).
+ *
+ * @param securityType One of the security types from {@link SecurityType}.
+ */
+ public void setSecurityParams(@SecurityType int securityType) {
+ // Clear all the bitsets.
+ allowedKeyManagement.clear();
+ allowedProtocols.clear();
+ allowedAuthAlgorithms.clear();
+ allowedPairwiseCiphers.clear();
+ allowedGroupCiphers.clear();
+ allowedGroupManagementCiphers.clear();
+ allowedSuiteBCiphers.clear();
+
+ switch (securityType) {
+ case SECURITY_TYPE_OPEN:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ break;
+ case SECURITY_TYPE_WEP:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+ break;
+ case SECURITY_TYPE_PSK:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ break;
+ case SECURITY_TYPE_EAP:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ break;
+ case SECURITY_TYPE_SAE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ requirePMF = true;
+ break;
+ case SECURITY_TYPE_EAP_SUITE_B:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
+ allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
+ allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ requirePMF = true;
+ break;
+ case SECURITY_TYPE_OWE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ requirePMF = true;
+ break;
+ default:
+ throw new IllegalArgumentException("unknown security type " + securityType);
+ }
+ }
+
/** @hide */
public static final int UNKNOWN_UID = -1;
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 089b59a2704c..c7180c1b1c57 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.IntRange;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -101,6 +102,11 @@ public class WifiInfo implements Parcelable {
private int mLinkSpeed;
/**
+ * Constant for unknown link speed.
+ */
+ public static final int LINK_SPEED_UNKNOWN = -1;
+
+ /**
* Tx(transmit) Link speed in Mbps
*/
private int mTxLinkSpeed;
@@ -214,7 +220,7 @@ public class WifiInfo implements Parcelable {
mNetworkId = -1;
mSupplicantState = SupplicantState.UNINITIALIZED;
mRssi = INVALID_RSSI;
- mLinkSpeed = -1;
+ mLinkSpeed = LINK_SPEED_UNKNOWN;
mFrequency = -1;
}
@@ -225,9 +231,9 @@ public class WifiInfo implements Parcelable {
setSSID(null);
setNetworkId(-1);
setRssi(INVALID_RSSI);
- setLinkSpeed(-1);
- setTxLinkSpeedMbps(-1);
- setRxLinkSpeedMbps(-1);
+ setLinkSpeed(LINK_SPEED_UNKNOWN);
+ setTxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
+ setRxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
@@ -369,8 +375,9 @@ public class WifiInfo implements Parcelable {
/**
* Returns the current link speed in {@link #LINK_SPEED_UNITS}.
- * @return the link speed or -1 if there is no valid value.
+ * @return the link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
* @see #LINK_SPEED_UNITS
+ * @see #LINK_SPEED_UNKNOWN
*/
public int getLinkSpeed() {
return mLinkSpeed;
@@ -384,8 +391,10 @@ public class WifiInfo implements Parcelable {
/**
* Returns the current transmit link speed in Mbps.
- * @return the Tx link speed or -1 if there is no valid value.
+ * @return the Tx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
+ * @see #LINK_SPEED_UNKNOWN
*/
+ @IntRange(from = -1)
public int getTxLinkSpeedMbps() {
return mTxLinkSpeed;
}
@@ -400,8 +409,10 @@ public class WifiInfo implements Parcelable {
/**
* Returns the current receive link speed in Mbps.
- * @return the Rx link speed or -1 if there is no valid value.
+ * @return the Rx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
+ * @see #LINK_SPEED_UNKNOWN
*/
+ @IntRange(from = -1)
public int getRxLinkSpeedMbps() {
return mRxLinkSpeed;
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 333b82ccd146..c99bd2e45dad 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -269,58 +269,26 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
}
- /**
- * Set defaults for the various low level credential type fields in the newly created
- * WifiConfiguration object.
- *
- * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
- * WifiConfiguration)}.
- *
- * @param configuration provided WifiConfiguration object.
- */
- private static void setDefaultsInWifiConfiguration(
- @NonNull WifiConfiguration configuration) {
- configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
- }
-
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
} else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
- // PMF mandatory for SAE.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
} else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
configuration.enterpriseConfig = mWpa2EnterpriseConfig;
} else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
- configuration.allowedGroupManagementCiphers.set(
- WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_RSA);
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
- // PMF mandatory.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
} else { // Open network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
}
@@ -330,7 +298,6 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
*/
private WifiConfiguration buildWifiConfiguration() {
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
- setDefaultsInWifiConfiguration(wifiConfiguration);
// WifiConfiguration.SSID needs quotes around unicode SSID.
if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 233fa2cb4fff..f02404fc1940 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -303,58 +303,26 @@ public final class WifiNetworkSuggestion implements Parcelable {
return this;
}
- /**
- * Set defaults for the various low level credential type fields in the newly created
- * WifiConfiguration object.
- *
- * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
- * WifiConfiguration)}.
- *
- * @param configuration provided WifiConfiguration object.
- */
- private static void setDefaultsInWifiConfiguration(
- @NonNull WifiConfiguration configuration) {
- configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
- }
-
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
} else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
- // PMF mandatory for SAE.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
} else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
configuration.enterpriseConfig = mWpa2EnterpriseConfig;
} else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
- configuration.allowedGroupManagementCiphers.set(
- WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_RSA);
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
- // PMF mandatory.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
} else { // Open network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
}
@@ -364,7 +332,6 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private WifiConfiguration buildWifiConfiguration() {
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
- setDefaultsInWifiConfiguration(wifiConfiguration);
// WifiConfiguration.SSID needs quotes around unicode SSID.
wifiConfiguration.SSID = "\"" + mSsid + "\"";
if (mBssid != null) {
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index acc0518dbca4..b73551fc62e0 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -259,8 +259,17 @@ public class WifiScanner {
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean ignoreLocationSettings;
+ /**
+ * This scan request will be hidden from app-ops noting for location information. This
+ * should only be used by FLP/NLP module on the device which is using the scan results to
+ * compute results for behalf on their clients. FLP/NLP module using this flag should ensure
+ * that they note in app-ops the eventual delivery of location information computed using
+ * these results to their client .
+ * {@hide}
+ */
+ @SystemApi
+ public boolean hideFromAppOps;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -279,6 +288,7 @@ public class WifiScanner {
dest.writeInt(isPnoScan ? 1 : 0);
dest.writeInt(type);
dest.writeInt(ignoreLocationSettings ? 1 : 0);
+ dest.writeInt(hideFromAppOps ? 1 : 0);
if (channels != null) {
dest.writeInt(channels.length);
for (int i = 0; i < channels.length; i++) {
@@ -314,6 +324,7 @@ public class WifiScanner {
settings.isPnoScan = in.readInt() == 1;
settings.type = in.readInt();
settings.ignoreLocationSettings = in.readInt() == 1;
+ settings.hideFromAppOps = in.readInt() == 1;
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index f931ad2bdf6d..479adbcb1a00 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -26,6 +26,7 @@ import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.regex.PatternSyntaxException;
/**
* A class representing a Wi-Fi P2p configuration for setting up a connection
@@ -252,7 +253,12 @@ public class WifiP2pConfig implements Parcelable {
* Specify the network name, a.k.a. group name,
* for creating or joining a group.
* <p>
- * Must be called - an empty network name is not valid.
+ * A network name shall begin with "DIRECT-xy". x and y are selected
+ * from the following character set: upper case letters, lower case
+ * letters and numbers.
+ * <p>
+ * Must be called - an empty network name or an network name
+ * not conforming to the P2P Group ID naming rule is not valid.
*
* @param networkName network name of a group.
* @return The builder to facilitate chaining
@@ -263,6 +269,14 @@ public class WifiP2pConfig implements Parcelable {
throw new IllegalArgumentException(
"network name must be non-empty.");
}
+ try {
+ if (!networkName.matches("^DIRECT-[a-zA-Z0-9]{2}.*")) {
+ throw new IllegalArgumentException(
+ "network name must starts with the prefix DIRECT-xy.");
+ }
+ } catch (PatternSyntaxException e) {
+ // can never happen (fixed pattern)
+ }
mNetworkName = networkName;
return this;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index bef33b769a75..feac0e598127 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -69,16 +69,6 @@ public class WifiNetworkSpecifierTest {
assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.NONE));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
}
/**
@@ -105,16 +95,6 @@ public class WifiNetworkSpecifierTest {
wifiNetworkSpecifier.bssidPatternMatcher.second);
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.WPA_PSK));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
}
@@ -150,16 +130,6 @@ public class WifiNetworkSpecifierTest {
.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.IEEE8021X));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
assertEquals(enterpriseConfig.getEapMethod(),
wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java
new file mode 100644
index 000000000000..560c88ee1d07
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.p2p;
+
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit test harness for {@link android.net.wifi.p2p.WifiP2pConfig}
+ */
+@SmallTest
+public class WifiP2pConfigTest {
+ /**
+ * Check network name setter
+ */
+ @Test
+ public void testBuilderInvalidNetworkName() throws Exception {
+ WifiP2pConfig.Builder b = new WifiP2pConfig.Builder();
+
+ // sunny case
+ try {
+ b.setNetworkName("DIRECT-ab-Hello");
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException");
+ }
+
+ // sunny case, no trailing string
+ try {
+ b.setNetworkName("DIRECT-WR");
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException");
+ }
+
+ // less than 9 characters.
+ try {
+ b.setNetworkName("DIRECT-z");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // not starts with DIRECT-xy.
+ try {
+ b.setNetworkName("ABCDEFGHIJK");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // not starts with uppercase DIRECT-xy
+ try {
+ b.setNetworkName("direct-ab");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // x and y are not selected from upper case letters, lower case letters or
+ // numbers.
+ try {
+ b.setNetworkName("direct-a?");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+ }
+}