summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp6
-rw-r--r--apct-tests/perftests/autofill/Android.mk2
-rw-r--r--apct-tests/perftests/autofill/AndroidManifest.xml2
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java21
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java28
-rw-r--r--apct-tests/perftests/utils/Android.mk2
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java3
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java2
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java9
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java7
-rw-r--r--api/current.txt62
-rw-r--r--api/system-current.txt109
-rw-r--r--api/test-current.txt15
-rw-r--r--cmds/bootanimation/BootAnimation.h4
-rw-r--r--cmds/idmap2/Android.bp1
-rw-r--r--cmds/statsd/Android.bp4
-rw-r--r--cmds/statsd/src/StatsService.cpp6
-rw-r--r--cmds/statsd/src/atoms.proto3
-rw-r--r--cmds/statsd/src/external/ResourceThermalManagerPuller.cpp17
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.cpp12
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.h3
-rw-r--r--cmds/statsd/tests/shell/ShellSubscriber_test.cpp2
-rw-r--r--cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java3
-rw-r--r--config/hiddenapi-greylist-max-p.txt75
-rw-r--r--config/hiddenapi-greylist.txt79
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java5
-rw-r--r--core/java/android/accounts/AccountManager.java12
-rw-r--r--core/java/android/accounts/AuthenticatorDescription.java5
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java8
-rw-r--r--core/java/android/app/ActivityTaskManager.java13
-rw-r--r--core/java/android/app/ActivityThread.java2
-rw-r--r--core/java/android/app/ActivityView.java12
-rw-r--r--core/java/android/app/ApplicationPackageManager.java4
-rw-r--r--core/java/android/app/Dialog.java2
-rw-r--r--core/java/android/app/Fragment.java2
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl6
-rw-r--r--core/java/android/app/Instrumentation.java3
-rw-r--r--core/java/android/app/ProgressDialog.java3
-rw-r--r--core/java/android/app/ResultInfo.java3
-rw-r--r--core/java/android/app/StatusBarManager.java31
-rw-r--r--core/java/android/app/SystemServiceRegistry.java20
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java27
-rw-r--r--core/java/android/app/assist/AssistContent.java15
-rw-r--r--core/java/android/app/job/JobWorkItem.java11
-rw-r--r--core/java/android/app/usage/ConfigurationStats.java13
-rw-r--r--core/java/android/app/usage/UsageEvents.java27
-rw-r--r--core/java/android/app/usage/UsageStats.java9
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java2
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java2
-rwxr-xr-xcore/java/android/bluetooth/BluetoothClass.java3
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java9
-rw-r--r--core/java/android/content/Context.java20
-rw-r--r--core/java/android/content/Entity.java5
-rw-r--r--core/java/android/content/Intent.java29
-rw-r--r--core/java/android/content/SyncAdapterType.java7
-rw-r--r--core/java/android/content/SyncInfo.java3
-rw-r--r--core/java/android/content/om/OverlayInfo.java3
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java25
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageInfo.java3
-rw-r--r--core/java/android/content/pm/PackageInfoLite.java3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java9
-rw-r--r--core/java/android/content/pm/PackageManager.java66
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java44
-rw-r--r--core/java/android/content/pm/PackageParser.java22
-rw-r--r--core/java/android/content/pm/PackageStats.java3
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java2
-rw-r--r--core/java/android/content/rollback/IRollbackManager.aidl41
-rw-r--r--core/java/android/content/rollback/PackageRollbackInfo.aidl (renamed from core/java/android/hardware/display/BrightnessCorrection.aidl)5
-rw-r--r--core/java/android/content/rollback/PackageRollbackInfo.java109
-rw-r--r--core/java/android/content/rollback/RollbackInfo.aidl18
-rw-r--r--core/java/android/content/rollback/RollbackInfo.java71
-rw-r--r--core/java/android/content/rollback/RollbackManager.java186
-rw-r--r--core/java/android/database/DatabaseUtils.java3
-rw-r--r--core/java/android/database/MatrixCursor.java5
-rw-r--r--core/java/android/database/sqlite/SQLiteQueryBuilder.java8
-rw-r--r--core/java/android/hardware/display/BrightnessConfiguration.java329
-rw-r--r--core/java/android/hardware/display/BrightnessCorrection.java245
-rw-r--r--core/java/android/hardware/display/ColorDisplayManager.java7
-rw-r--r--core/java/android/hardware/face/FaceManager.java5
-rw-r--r--core/java/android/hardware/hdmi/HdmiAudioSystemClient.java3
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java13
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java5
-rw-r--r--core/java/android/net/ConnectivityManager.java3
-rw-r--r--core/java/android/net/LinkAddress.java5
-rw-r--r--core/java/android/net/LinkProperties.java5
-rw-r--r--core/java/android/net/NetworkAgent.java3
-rw-r--r--core/java/android/net/NetworkFactory.java5
-rw-r--r--core/java/android/net/NetworkPolicyManager.java5
-rw-r--r--core/java/android/net/NetworkRequest.java3
-rw-r--r--core/java/android/net/NetworkStats.java26
-rw-r--r--core/java/android/net/RouteInfo.java5
-rw-r--r--core/java/android/net/WebAddress.java3
-rw-r--r--core/java/android/net/http/SslError.java5
-rw-r--r--core/java/android/nfc/INfcCardEmulation.aidl2
-rw-r--r--core/java/android/nfc/NfcAdapter.java104
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java70
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulation.java103
-rw-r--r--core/java/android/os/AppZygote.java119
-rw-r--r--core/java/android/os/Environment.java5
-rw-r--r--core/java/android/os/GraphicsEnvironment.java17
-rw-r--r--core/java/android/os/Process.java27
-rw-r--r--core/java/android/os/UserHandle.java25
-rw-r--r--core/java/android/os/ZygoteProcess.java50
-rw-r--r--core/java/android/os/storage/DiskInfo.java5
-rw-r--r--core/java/android/os/storage/StorageManager.java1
-rw-r--r--core/java/android/permission/IPermissionController.aidl (renamed from core/java/android/permission/IRuntimePermissionPresenter.aidl)4
-rw-r--r--core/java/android/permission/PermissionControllerManager.java (renamed from core/java/android/permission/RuntimePermissionPresenter.java)75
-rw-r--r--core/java/android/permission/PermissionControllerService.java (renamed from core/java/android/permission/RuntimePermissionPresenterService.java)44
-rw-r--r--core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java3
-rw-r--r--core/java/android/provider/Downloads.java9
-rw-r--r--core/java/android/provider/MediaStore.java178
-rw-r--r--core/java/android/provider/Settings.java25
-rw-r--r--core/java/android/service/autofill/CompositeUserData.java211
-rw-r--r--core/java/android/service/autofill/FieldClassificationUserData.java64
-rw-r--r--core/java/android/service/autofill/FillResponse.java3
-rw-r--r--core/java/android/service/autofill/UserData.java9
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java6
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java11
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rw-r--r--core/java/android/text/method/HideReturnsTransformationMethod.java3
-rw-r--r--core/java/android/text/method/PasswordTransformationMethod.java3
-rw-r--r--core/java/android/text/style/BulletSpan.java7
-rw-r--r--core/java/android/util/DebugUtils.java3
-rw-r--r--core/java/android/util/Range.java2
-rw-r--r--core/java/android/util/Slog.java3
-rw-r--r--core/java/android/util/TimeUtils.java5
-rw-r--r--core/java/android/view/AccessibilityIterators.java3
-rw-r--r--core/java/android/view/IWindowSession.aidl6
-rw-r--r--core/java/android/view/InsetsController.java31
-rw-r--r--core/java/android/view/InsetsSource.java4
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java34
-rw-r--r--core/java/android/view/InsetsState.java29
-rw-r--r--core/java/android/view/LayoutInflater.java270
-rw-r--r--core/java/android/view/SurfaceControl.java18
-rw-r--r--core/java/android/view/SurfaceView.java12
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewGroup.java2
-rw-r--r--core/java/android/view/Window.java5
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java36
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java72
-rw-r--r--core/java/android/webkit/ConsoleMessage.java9
-rw-r--r--core/java/android/webkit/WebView.java2
-rw-r--r--core/java/android/webkit/WebViewDelegate.java14
-rw-r--r--core/java/android/webkit/WebViewZygote.java1
-rw-r--r--core/java/android/widget/AbsListView.java7
-rw-r--r--core/java/android/widget/Gallery.java9
-rw-r--r--core/java/android/widget/ListView.java9
-rw-r--r--core/java/android/widget/MediaController.java9
-rw-r--r--core/java/android/widget/PopupWindow.java4
-rw-r--r--core/java/android/widget/SimpleAdapter.java3
-rw-r--r--core/java/android/widget/SimpleCursorAdapter.java3
-rw-r--r--core/java/android/widget/TextView.java6
-rw-r--r--core/java/android/widget/VideoView.java4
-rw-r--r--core/java/com/android/internal/accessibility/AccessibilityShortcutController.java10
-rw-r--r--core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java7
-rw-r--r--core/java/com/android/internal/net/VpnProfile.java3
-rw-r--r--core/java/com/android/internal/os/AppZygoteInit.java105
-rw-r--r--core/java/com/android/internal/os/AtomicFile.java3
-rw-r--r--core/java/com/android/internal/os/ChildZygoteInit.java99
-rw-r--r--core/java/com/android/internal/os/RoSystemProperties.java8
-rw-r--r--core/java/com/android/internal/os/WebViewZygoteInit.java51
-rw-r--r--core/java/com/android/internal/os/Zygote.java6
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java41
-rw-r--r--core/java/com/android/internal/util/AsyncChannel.java5
-rw-r--r--core/java/com/android/internal/util/JournaledFile.java9
-rw-r--r--core/jni/android/graphics/text/LineBreaker.cpp2
-rw-r--r--core/jni/android/graphics/text/MeasuredText.cpp2
-rw-r--r--core/jni/android_media_AudioSystem.cpp51
-rw-r--r--core/jni/android_view_SurfaceControl.cpp13
-rw-r--r--core/proto/android/os/enums.proto11
-rw-r--r--core/proto/android/providers/settings/global.proto8
-rw-r--r--core/proto/android/server/activitymanagerservice.proto1
-rw-r--r--core/res/AndroidManifest.xml17
-rw-r--r--core/res/res/layout/chooser_grid.xml6
-rw-r--r--core/res/res/values-land/dimens_permission_controller.xml24
-rw-r--r--core/res/res/values-mcc302-mnc220/config.xml13
-rw-r--r--core/res/res/values-mcc302-mnc221/config.xml36
-rw-r--r--core/res/res/values-mcc302-mnc370/config.xml13
-rw-r--r--core/res/res/values-mcc302-mnc610/config.xml13
-rw-r--r--core/res/res/values-mcc302-mnc640/config.xml34
-rw-r--r--core/res/res/values-mcc302-mnc720/config.xml13
-rw-r--r--core/res/res/values-night/themes_permission_controller.xml32
-rw-r--r--core/res/res/values-port/dimens_permission_controller.xml23
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml6
-rw-r--r--core/res/res/values/config.xml16
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/styles_device_defaults.xml24
-rw-r--r--core/res/res/values/styles_permission_controller.xml98
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/res/res/values/themes_device_defaults.xml41
-rw-r--r--core/res/res/values/themes_permission_controller.xml40
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java3
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java14
-rw-r--r--core/tests/featureflagtests/Android.mk2
-rw-r--r--core/tests/featureflagtests/AndroidManifest.xml2
-rw-r--r--core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java5
-rw-r--r--graphics/java/android/graphics/Paint.java3
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java3
-rw-r--r--keystore/java/android/security/KeyStore.java5
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/DisplayListOps.in6
-rw-r--r--libs/hwui/RecordingCanvas.cpp82
-rw-r--r--libs/hwui/RecordingCanvas.h4
-rw-r--r--libs/hwui/SkiaCanvas.cpp10
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp23
-rw-r--r--libs/hwui/WebViewFunctorManager.h5
-rw-r--r--libs/hwui/private/hwui/WebViewFunctor.h15
-rw-r--r--libs/hwui/tests/common/TestUtils.h8
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp12
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp4
-rw-r--r--libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp18
-rw-r--r--location/java/android/location/GpsStatus.java3
-rw-r--r--location/java/android/location/Location.java3
-rw-r--r--location/java/android/location/LocationManager.java2
-rw-r--r--location/java/android/location/LocationRequest.java21
-rw-r--r--media/java/android/media/AudioManager.java51
-rw-r--r--media/java/android/media/AudioSystem.java7
-rw-r--r--media/java/android/media/CamcorderProfile.java3
-rw-r--r--media/java/android/media/Controller2Link.aidl19
-rw-r--r--media/java/android/media/Controller2Link.java171
-rw-r--r--media/java/android/media/ExifInterface.java9
-rw-r--r--media/java/android/media/IAudioService.aidl5
-rw-r--r--media/java/android/media/IMediaController2.aidl38
-rw-r--r--media/java/android/media/IMediaSession2.aidl39
-rw-r--r--media/java/android/media/MediaCodecInfo.java2
-rw-r--r--media/java/android/media/MediaConstants.java32
-rw-r--r--media/java/android/media/MediaController2.java369
-rw-r--r--media/java/android/media/MediaItem2.java26
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java7
-rw-r--r--media/java/android/media/MediaPlayer.java79
-rw-r--r--media/java/android/media/MediaRecorder.java15
-rw-r--r--media/java/android/media/MediaScanner.java11
-rw-r--r--media/java/android/media/MediaSession2.java715
-rw-r--r--media/java/android/media/Session2Command.aidl19
-rw-r--r--media/java/android/media/Session2Command.java479
-rw-r--r--media/java/android/media/Session2CommandGroup.java131
-rw-r--r--media/java/android/media/Session2Link.java190
-rw-r--r--media/java/android/media/Session2Token.aidl19
-rw-r--r--media/java/android/media/Session2Token.java53
-rw-r--r--media/java/android/media/ThumbnailUtils.java13
-rw-r--r--media/java/android/media/audiopolicy/AudioMix.java14
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java75
-rw-r--r--media/java/android/media/session/ISessionController.aidl7
-rw-r--r--media/java/android/media/session/ISessionManager.aidl9
-rw-r--r--media/java/android/media/session/MediaController.java70
-rw-r--r--media/java/android/media/session/MediaSessionManager.java36
-rw-r--r--media/jni/Android.bp15
-rw-r--r--media/tests/MtpTests/Android.mk2
-rw-r--r--media/tests/MtpTests/AndroidManifest.xml2
-rw-r--r--media/tests/MtpTests/AndroidTest.xml2
-rw-r--r--media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java11
-rw-r--r--native/webview/plat_support/Android.bp1
-rw-r--r--native/webview/plat_support/draw_fn.h18
-rw-r--r--native/webview/plat_support/draw_functor.cpp144
-rw-r--r--native/webview/plat_support/jni_entry_point.cpp2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java12
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java41
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java5
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java10
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java73
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java26
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java58
-rw-r--r--packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml62
-rw-r--r--packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java176
-rw-r--r--packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java148
-rw-r--r--packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml5
-rw-r--r--packages/SettingsLib/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java13
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java162
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java129
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java141
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java7
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java30
-rw-r--r--packages/SettingsProvider/test/Android.mk2
-rw-r--r--packages/SettingsProvider/test/AndroidManifest.xml2
-rw-r--r--packages/SettingsProvider/test/AndroidTest.xml2
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java7
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java5
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java5
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java6
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java11
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml25
-rw-r--r--packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml22
-rw-r--r--packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml42
-rw-r--r--packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml42
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java7
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java)81
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.pngbin414 -> 0 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.pngbin557 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.pngbin178 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-land/search_panel_scrim.xml25
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.pngbin304 -> 0 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.pngbin377 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.pngbin158 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml10
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.pngbin205 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.pngbin170 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.pngbin263 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.pngbin263 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml25
-rw-r--r--packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.pngbin5152 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.pngbin536 -> 0 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.pngbin755 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.pngbin234 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.pngbin267 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/dismiss_all_shape.xml39
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_error_to_face.xml517
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml637
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml637
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml178
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_face_to_error.xml473
-rw-r--r--packages/SystemUI/res/drawable/face_dialog_icon.xml24
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml476
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml809
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_icon.xml107
-rw-r--r--packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_cast.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_chevron_left.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_data_off.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_data_on.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_data_unavailable.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_expand_less.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_expand_more.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_history.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_back.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_battery_saver.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_lock.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_lock_open.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_network_logging.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml31
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml35
-rw-r--r--packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml128
-rw-r--r--packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml35
-rw-r--r--packages/SystemUI/res/drawable/ic_sim.xml42
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_speaker_group.xml32
-rw-r--r--packages/SystemUI/res/drawable/ic_swap.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_tv.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_zen_all.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_zen_important.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_zen_none.xml25
-rw-r--r--packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml21
-rw-r--r--packages/SystemUI/res/drawable/notification_expand_more.xml25
-rw-r--r--packages/SystemUI/res/drawable/pip_dismiss.xml24
-rw-r--r--packages/SystemUI/res/drawable/pip_notification_icon.xml25
-rw-r--r--packages/SystemUI/res/drawable/pop_ball.xml29
-rw-r--r--packages/SystemUI/res/drawable/pop_belt.xml33
-rw-r--r--packages/SystemUI/res/drawable/pop_droid.xml33
-rw-r--r--packages/SystemUI/res/drawable/pop_pizza.xml45
-rw-r--r--packages/SystemUI/res/drawable/pop_stripes.xml36
-rw-r--r--packages/SystemUI/res/drawable/pop_swirl.xml57
-rw-r--r--packages/SystemUI/res/drawable/pop_vortex.xml27
-rw-r--r--packages/SystemUI/res/drawable/pop_vortex2.xml27
-rw-r--r--packages/SystemUI/res/drawable/qs_subhead_caret.xml25
-rw-r--r--packages/SystemUI/res/drawable/quick_header_bg.xml21
-rw-r--r--packages/SystemUI/res/drawable/scorecard_gameover.xml10
-rw-r--r--packages/SystemUI/res/drawable/stat_notify_more.xml24
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml66
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml66
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml24
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_no_sims.xml30
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_in.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_inout.xml31
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_signal_out.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_in.xml27
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml31
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_wifi_out.xml27
-rw-r--r--packages/SystemUI/res/drawable/sun2.xml24
-rw-r--r--packages/SystemUI/res/drawable/volume_dialog_background.xml18
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/DependencyBinder.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/DependencyProvider.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java309
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java147
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/dock/DockManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java312
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java148
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java189
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java216
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java336
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java420
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java12
-rw-r--r--packages/overlays/AccentColorBlackOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/AccentColorGreenOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/Android.mk31
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml21
-rw-r--r--packages/overlays/FontArvoLatoOverlay/Android.mk31
-rw-r--r--packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontArvoLatoOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontArvoLatoOverlay/res/values/strings.xml21
-rw-r--r--packages/overlays/FontRubikRubikOverlay/Android.mk31
-rw-r--r--packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml31
-rw-r--r--packages/overlays/FontRubikRubikOverlay/res/values/config.xml28
-rw-r--r--packages/overlays/FontRubikRubikOverlay/res/values/strings.xml21
-rw-r--r--packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml2
-rw-r--r--packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/IconShapeSquareOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml2
-rw-r--r--packages/overlays/IconShapeTeardropOverlay/res/values/config.xml2
-rw-r--r--packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml2
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto5
-rw-r--r--services/accessibility/TEST_MAPPING12
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java18
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java58
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java78
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerFiles.java45
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java72
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java11
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java566
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java71
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java68
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java27
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java6
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java9
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java4
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java25
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java261
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java17
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java84
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java21
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java199
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java124
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java374
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerShellCommand.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayTransformManager.java4
-rw-r--r--services/core/java/com/android/server/display/PersistentDataStore.java95
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java14
-rw-r--r--services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java284
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java289
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java72
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java65
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java115
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java10
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java153
-rw-r--r--services/core/java/com/android/server/notification/NotificationShellCmd.java483
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java6
-rw-r--r--services/core/java/com/android/server/pm/ModuleInfoProvider.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java75
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java124
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java344
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageVerificationState.java26
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java97
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java13
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java36
-rw-r--r--services/core/java/com/android/server/rollback/PackageRollbackData.java49
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerService.java52
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java832
-rw-r--r--services/core/java/com/android/server/security/VerityUtils.java17
-rw-r--r--services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java (renamed from services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java)18
-rw-r--r--services/core/java/com/android/server/signedconfig/SignedConfigService.java22
-rw-r--r--services/core/java/com/android/server/slice/SliceClientPermissions.java9
-rw-r--r--services/core/java/com/android/server/slice/SlicePermissionManager.java11
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java42
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java83
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java59
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java39
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java5
-rw-r--r--services/core/java/com/android/server/wm/BarController.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java1
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java6
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java109
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java61
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java22
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java46
-rw-r--r--services/core/java/com/android/server/wm/Session.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java19
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java27
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java9
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/BroadcastRadio/NativeCallbackThread.h2
-rw-r--r--services/core/jni/BroadcastRadio/Tuner.cpp3
-rw-r--r--services/core/jni/com_android_server_am_BatteryStatsService.cpp414
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp2
-rw-r--r--services/core/jni/com_android_server_storage_AppFuseBridge.cpp2
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp2
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java14
-rw-r--r--services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java3
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java76
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java13
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java270
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java52
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java43
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java17
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java2
-rw-r--r--startop/view_compiler/TEST_MAPPING4
-rw-r--r--startop/view_compiler/main.cc1
-rw-r--r--startop/view_compiler/util.cc6
-rw-r--r--startop/view_compiler/util.h12
-rw-r--r--startop/view_compiler/util_test.cc14
-rw-r--r--telecomm/java/android/telecom/Connection.java5
-rw-r--r--telecomm/java/android/telecom/PhoneAccountHandle.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java125
-rw-r--r--telephony/java/android/telephony/CellIdentityLte.java3
-rw-r--r--telephony/java/android/telephony/CellInfoCdma.java3
-rw-r--r--telephony/java/android/telephony/CellInfoLte.java5
-rw-r--r--telephony/java/android/telephony/CellSignalStrength.java3
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthWcdma.java74
-rw-r--r--telephony/java/android/telephony/NeighboringCellInfo.java11
-rw-r--r--telephony/java/android/telephony/PreciseDataConnectionState.java42
-rw-r--r--telephony/java/android/telephony/RadioAccessFamily.java3
-rw-r--r--telephony/java/android/telephony/Rlog.java2
-rw-r--r--telephony/java/android/telephony/ServiceState.java34
-rw-r--r--telephony/java/android/telephony/SmsManager.java3
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java26
-rw-r--r--telephony/java/android/telephony/VoLteServiceState.java3
-rw-r--r--telephony/java/android/telephony/cdma/CdmaCellLocation.java13
-rw-r--r--telephony/java/android/telephony/gsm/GsmCellLocation.java3
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java2
-rw-r--r--telephony/java/android/telephony/ims/Rcs1To1Thread.aidl20
-rw-r--r--telephony/java/android/telephony/ims/Rcs1To1Thread.java56
-rw-r--r--telephony/java/android/telephony/ims/RcsFileTransferPart.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsFileTransferPart.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThread.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsGroupThread.java52
-rw-r--r--telephony/java/android/telephony/ims/RcsIncomingMessage.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsIncomingMessage.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsLocationPart.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsLocationPart.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsManager.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsManager.java2
-rw-r--r--telephony/java/android/telephony/ims/RcsMessage.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsMessage.java25
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageStore.java85
-rw-r--r--telephony/java/android/telephony/ims/RcsMultiMediaPart.java50
-rw-r--r--telephony/java/android/telephony/ims/RcsMultimediaPart.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsOutgoingMessage.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsPart.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsPart.java25
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipant.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipant.java60
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java49
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsParticipantEvent.java25
-rw-r--r--telephony/java/android/telephony/ims/RcsTextPart.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsTextPart.java48
-rw-r--r--telephony/java/android/telephony/ims/RcsThread.aidl2
-rw-r--r--telephony/java/android/telephony/ims/RcsThread.java63
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadEvent.java25
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java49
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java49
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java49
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java49
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl (renamed from packages/SystemUI/res/drawable/qs_tile_background.xml)18
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java52
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl (renamed from packages/SystemUI/res/drawable/header_dot.xml)20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryParameters.java225
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThreadQueryResult.java92
-rw-r--r--telephony/java/android/telephony/ims/aidl/IRcs.aidl15
-rw-r--r--telephony/java/com/android/internal/telephony/GsmAlphabet.java3
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl10
-rw-r--r--telephony/java/com/android/internal/telephony/OperatorInfo.java3
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneConstants.java2
-rw-r--r--telephony/java/com/android/internal/telephony/SmsMessageBase.java11
-rw-r--r--test-mock/src/android/test/mock/MockContentProvider.java9
-rw-r--r--test-mock/src/android/test/mock/MockPackageManager.java3
-rw-r--r--tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java5
-rw-r--r--tests/RcsTests/Android.mk2
-rw-r--r--tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java (renamed from tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java)2
-rw-r--r--tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java53
-rw-r--r--tests/RollbackTest/Android.mk81
-rw-r--r--tests/RollbackTest/AndroidManifest.xml (renamed from packages/SystemUI/res/drawable/tv_pip_outline.xml)21
-rw-r--r--tests/RollbackTest/RollbackTest.xml (renamed from packages/SystemUI/res/drawable/ic_notify_button_bg.xml)17
-rw-r--r--tests/RollbackTest/TestApp/Av1.xml36
-rw-r--r--tests/RollbackTest/TestApp/Av2.xml36
-rw-r--r--tests/RollbackTest/TestApp/Bv1.xml36
-rw-r--r--tests/RollbackTest/TestApp/Bv2.xml36
-rw-r--r--tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java37
-rw-r--r--tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java106
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java59
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java71
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java541
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java202
-rw-r--r--tests/net/java/android/net/NetworkStatsTest.java12
-rw-r--r--tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java17
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat4
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after4
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before4
-rw-r--r--tests/net/res/raw/xt_qtaguid_with_clat_simple5
-rw-r--r--tools/aapt/ConfigDescription.h2
-rw-r--r--tools/aapt2/Android.bp6
-rw-r--r--tools/aapt2/Debug.cpp2
-rw-r--r--tools/aapt2/Resource.h4
-rw-r--r--tools/aapt2/cmd/Command.cpp105
-rw-r--r--tools/aapt2/cmd/Command.h82
-rw-r--r--tools/aapt2/cmd/Command_test.cpp97
-rw-r--r--tools/aapt2/cmd/Compile.cpp2
-rw-r--r--tools/aapt2/cmd/Compile.h13
-rw-r--r--tools/aapt2/cmd/Convert.cpp29
-rw-r--r--tools/aapt2/cmd/Convert.h17
-rw-r--r--tools/aapt2/cmd/Convert_test.cpp98
-rw-r--r--tools/aapt2/cmd/Link.cpp7
-rw-r--r--tools/aapt2/cmd/Link.h23
-rw-r--r--tools/aapt2/cmd/Link_test.cpp78
-rw-r--r--tools/aapt2/cmd/Optimize.h7
-rw-r--r--tools/aapt2/integration-tests/CommandTests/android-28.jarbin0 -> 31949393 bytes
-rw-r--r--tools/aapt2/java/ProguardRules.h2
-rw-r--r--tools/aapt2/link/XmlCompatVersioner.h4
-rw-r--r--tools/aapt2/process/SymbolTable.h2
-rw-r--r--tools/aapt2/test/Common.h4
-rw-r--r--tools/aapt2/test/Fixture.cpp154
-rw-r--r--tools/aapt2/test/Fixture.h96
-rw-r--r--tools/aapt2/test/Test.h1
-rw-r--r--tools/aapt2/util/Files.cpp11
-rw-r--r--tools/aapt2/util/Files.h3
-rw-r--r--tools/aapt2/util/Maybe.h8
-rw-r--r--wifi/java/android/net/wifi/DppStatusCallback.java166
-rw-r--r--wifi/java/android/net/wifi/IDppCallback.aidl48
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl9
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java3
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java3
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java151
-rw-r--r--wifi/java/android/net/wifi/aware/PeerHandle.java30
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pGroup.java28
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java11
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java3
-rw-r--r--wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java3
-rw-r--r--wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java5
-rw-r--r--wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java3
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java20
772 files changed, 22483 insertions, 9605 deletions
diff --git a/Android.bp b/Android.bp
index 4211162d523f..eb9cbbb136f9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -151,6 +151,7 @@ java_defaults {
"core/java/android/content/pm/dex/IArtManager.aidl",
"core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl",
"core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl",
+ "core/java/android/content/rollback/IRollbackManager.aidl",
"core/java/android/database/IContentObserver.aidl",
"core/java/android/debug/IAdbManager.aidl",
"core/java/android/debug/IAdbTransport.aidl",
@@ -268,7 +269,7 @@ java_defaults {
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
- "core/java/android/permission/IRuntimePermissionPresenter.aidl",
+ "core/java/android/permission/IPermissionController.aidl",
"core/java/android/rolecontrollerservice/IRoleControllerService.aidl",
":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
@@ -461,11 +462,13 @@ java_defaults {
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",
"media/java/android/media/IAudioServerStateDispatcher.aidl",
+ "media/java/android/media/IMediaController2.aidl",
"media/java/android/media/IMediaHTTPConnection.aidl",
"media/java/android/media/IMediaHTTPService.aidl",
"media/java/android/media/IMediaResourceMonitor.aidl",
"media/java/android/media/IMediaRouterClient.aidl",
"media/java/android/media/IMediaRouterService.aidl",
+ "media/java/android/media/IMediaSession2.aidl",
"media/java/android/media/IMediaScannerListener.aidl",
"media/java/android/media/IMediaScannerService.aidl",
"media/java/android/media/IPlaybackConfigDispatcher.aidl",
@@ -631,6 +634,7 @@ java_defaults {
"wifi/java/android/net/wifi/rtt/IRttCallback.aidl",
"wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
"wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
+ "wifi/java/android/net/wifi/IDppCallback.aidl",
"wifi/java/android/net/wifi/IWifiScanner.aidl",
"packages/services/PacProcessor/com/android/net/IProxyService.aidl",
"packages/services/Proxy/com/android/net/IProxyCallback.aidl",
diff --git a/apct-tests/perftests/autofill/Android.mk b/apct-tests/perftests/autofill/Android.mk
index 28555a0d5ca5..f4da40b3175a 100644
--- a/apct-tests/perftests/autofill/Android.mk
+++ b/apct-tests/perftests/autofill/Android.mk
@@ -22,7 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
+ androidx.test.rules \
androidx.annotation_annotation \
apct-perftests-utils
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index e706a32ad0c8..9c8abc32eb72 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -35,6 +35,6 @@
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.perftests.autofill"/>
</manifest>
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
index 86a5c109f95a..6979f0f0875d 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
@@ -16,34 +16,23 @@
package android.view.autofill;
+import static org.junit.Assert.assertTrue;
+
import android.os.Looper;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.SettingsHelper;
import android.perftests.utils.SettingsStateKeeperRule;
-import android.perftests.utils.ShellHelper;
-import android.view.View;
import android.perftests.utils.StubActivity;
import android.provider.Settings;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
-
-import com.android.perftests.autofill.R;
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
-import org.junit.Test;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertTrue;
/**
* Base class for all autofill tests.
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
index 62662e477fd8..80908266c5c0 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -16,33 +16,17 @@
package android.view.autofill;
-import android.app.Activity;
-import android.os.Looper;
-import android.os.Bundle;
-import android.perftests.utils.PerfStatusReporter;
-import android.util.Log;
-import android.view.View;
-import android.widget.EditText;
+import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN;
+import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN;
+
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.StubActivity;
-import android.provider.Settings;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
-import com.android.perftests.autofill.R;
+import android.view.View;
+import android.widget.EditText;
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
+import com.android.perftests.autofill.R;
import org.junit.Test;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-
-import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN;
-import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN;
public class LoginTest extends AbstractAutofillPerfTestCase {
diff --git a/apct-tests/perftests/utils/Android.mk b/apct-tests/perftests/utils/Android.mk
index 604f0adbe23e..19f83c8f5bb0 100644
--- a/apct-tests/perftests/utils/Android.mk
+++ b/apct-tests/perftests/utils/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
+ androidx.test.rules \
androidx.annotation_annotation
# Build all java files in the java subdirectory
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index da17818bbda0..93bf541d02b4 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -20,9 +20,10 @@ import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
import android.os.Debug;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
index 0de6f1d944ff..8187c6fa63d5 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
@@ -16,7 +16,7 @@
package android.perftests.utils;
-import android.support.test.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
index 4b7b98da442b..d54a85147bf3 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
@@ -16,16 +16,17 @@
package android.perftests.utils;
-import android.support.test.InstrumentationRegistry;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
/**
* Use this rule to make sure we report the status after the test success.
*
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
index 895547df0393..7b52576c1abd 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
@@ -17,14 +17,13 @@ package android.perftests.utils;
import android.app.UiAutomation;
import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
-import android.util.Log;
-
-import java.io.FileInputStream;
import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+
+import java.io.FileInputStream;
/**
* Provides Shell-based utilities such as running a command.
diff --git a/api/current.txt b/api/current.txt
index 465739457cf0..13311d4980da 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11598,8 +11598,11 @@ package android.content.pm {
field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
+ field public static final java.lang.String FEATURE_NFC_BEAM = "android.sofware.nfc.beam";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
+ field public static final java.lang.String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
+ field public static final java.lang.String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC = "android.hardware.nfc.uicc";
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
@@ -24939,6 +24942,25 @@ package android.media {
field public static final int TYPE_STRING = 4; // 0x4
}
+ public final class MediaItem2 implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getEndPosition();
+ method public android.media.MediaMetadata getMetadata();
+ method public long getStartPosition();
+ method public void setMetadata(android.media.MediaMetadata);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.MediaItem2> CREATOR;
+ field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+ }
+
+ public static class MediaItem2.Builder {
+ ctor public MediaItem2.Builder();
+ method public android.media.MediaItem2 build();
+ method public android.media.MediaItem2.Builder setEndPosition(long);
+ method public android.media.MediaItem2.Builder setMetadata(android.media.MediaMetadata);
+ method public android.media.MediaItem2.Builder setStartPosition(long);
+ }
+
public final class MediaMetadata implements android.os.Parcelable {
method public boolean containsKey(java.lang.String);
method public int describeContents();
@@ -29555,6 +29577,7 @@ package android.net.wifi {
method public int getWifiState();
method public boolean is5GHzBandSupported();
method public boolean isDeviceToApRttSupported();
+ method public boolean isDppSupported();
method public boolean isEnhancedPowerReportingSupported();
method public boolean isOweSupported();
method public boolean isP2pSupported();
@@ -29750,7 +29773,10 @@ package android.net.wifi.aware {
method public void onIdentityChanged(byte[]);
}
- public class PeerHandle {
+ public final class PeerHandle implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PeerHandle> CREATOR;
}
public final class PublishConfig implements android.os.Parcelable {
@@ -30009,6 +30035,7 @@ package android.net.wifi.p2p {
ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup);
method public int describeContents();
method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getClientList();
+ method public int getFrequency();
method public java.lang.String getInterface();
method public java.lang.String getNetworkName();
method public android.net.wifi.p2p.WifiP2pDevice getOwner();
@@ -30285,15 +30312,16 @@ package android.nfc {
method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+ method public java.util.List<java.lang.String> getSupportedOffHostSecureElements();
method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
- method public boolean invokeBeam(android.app.Activity);
+ method public deprecated boolean invokeBeam(android.app.Activity);
method public boolean isEnabled();
- method public boolean isNdefPushEnabled();
- method public void setBeamPushUris(android.net.Uri[], android.app.Activity);
- method public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
- method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
- method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
- method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
+ method public deprecated boolean isNdefPushEnabled();
+ method public deprecated void setBeamPushUris(android.net.Uri[], android.app.Activity);
+ method public deprecated void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
+ method public deprecated void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+ method public deprecated void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+ method public deprecated void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
field public static final java.lang.String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
field public static final java.lang.String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
field public static final java.lang.String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
@@ -30320,15 +30348,15 @@ package android.nfc {
field public static final int STATE_TURNING_ON = 2; // 0x2
}
- public static abstract interface NfcAdapter.CreateBeamUrisCallback {
+ public static abstract deprecated interface NfcAdapter.CreateBeamUrisCallback {
method public abstract android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
}
- public static abstract interface NfcAdapter.CreateNdefMessageCallback {
+ public static abstract deprecated interface NfcAdapter.CreateNdefMessageCallback {
method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
}
- public static abstract interface NfcAdapter.OnNdefPushCompleteCallback {
+ public static abstract deprecated interface NfcAdapter.OnNdefPushCompleteCallback {
method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
}
@@ -30376,8 +30404,10 @@ package android.nfc.cardemulation {
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
method public boolean registerAidsForService(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public boolean removeAidsForService(android.content.ComponentName, java.lang.String);
+ method public boolean setOffHostForService(android.content.ComponentName, java.lang.String);
method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
method public boolean supportsAidPrefixRegistration();
+ method public boolean unsetOffHostForService(android.content.ComponentName);
method public boolean unsetPreferredService(android.app.Activity);
field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
field public static final java.lang.String CATEGORY_OTHER = "other";
@@ -37854,7 +37884,11 @@ package android.provider {
method public static java.lang.String getVolumeName(android.net.Uri);
method public static android.provider.MediaStore.PendingSession openPending(android.content.Context, android.net.Uri);
method public static android.net.Uri setIncludePending(android.net.Uri);
+ method public static android.net.Uri setIncludeTrashed(android.net.Uri);
method public static android.net.Uri setRequireOriginal(android.net.Uri);
+ method public static void trash(android.content.Context, android.net.Uri);
+ method public static void trash(android.content.Context, android.net.Uri, long);
+ method public static void untrash(android.content.Context, android.net.Uri);
field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
field public static final java.lang.String ACTION_REVIEW = "android.provider.action.REVIEW";
@@ -38033,6 +38067,7 @@ package android.provider {
}
public static abstract interface MediaStore.DownloadColumns implements android.provider.MediaStore.MediaColumns {
+ field public static final java.lang.String DESCRIPTION = "description";
field public static final java.lang.String DOWNLOAD_URI = "download_uri";
field public static final java.lang.String REFERER_URI = "referer_uri";
}
@@ -38077,6 +38112,7 @@ package android.provider {
field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
field public static final java.lang.String ORIENTATION = "orientation";
field public static final deprecated java.lang.String PICASA_ID = "picasa_id";
+ field public static final java.lang.String SECONDARY_BUCKET_ID = "secondary_bucket_id";
}
public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
@@ -38121,11 +38157,13 @@ package android.provider {
public static abstract interface MediaStore.MediaColumns implements android.provider.BaseColumns {
field public static final deprecated java.lang.String DATA = "_data";
field public static final java.lang.String DATE_ADDED = "date_added";
+ field public static final java.lang.String DATE_EXPIRES = "date_expires";
field public static final java.lang.String DATE_MODIFIED = "date_modified";
field public static final java.lang.String DISPLAY_NAME = "_display_name";
field public static final java.lang.String HASH = "_hash";
field public static final java.lang.String HEIGHT = "height";
field public static final java.lang.String IS_PENDING = "is_pending";
+ field public static final java.lang.String IS_TRASHED = "is_trashed";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String OWNER_PACKAGE_NAME = "owner_package_name";
field public static final java.lang.String SIZE = "_size";
@@ -38201,6 +38239,7 @@ package android.provider {
field public static final deprecated java.lang.String LONGITUDE = "longitude";
field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
field public static final java.lang.String RESOLUTION = "resolution";
+ field public static final java.lang.String SECONDARY_BUCKET_ID = "secondary_bucket_id";
field public static final java.lang.String TAGS = "tags";
}
@@ -42911,6 +42950,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final java.lang.String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
diff --git a/api/system-current.txt b/api/system-current.txt
index f7ea8be5c4f5..e79ede8dc9b7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -62,6 +62,7 @@ package android {
field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
+ field public static final java.lang.String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
field public static final java.lang.String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
@@ -94,6 +95,7 @@ package android {
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
+ field public static final java.lang.String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final java.lang.String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
@@ -1038,6 +1040,7 @@ package android.content {
field public static final java.lang.String OEM_LOCK_SERVICE = "oem_lock";
field public static final java.lang.String PERMISSION_SERVICE = "permission";
field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
+ field public static final java.lang.String ROLLBACK_SERVICE = "rollback";
field public static final java.lang.String SECURE_ELEMENT_SERVICE = "secure_element";
field public static final java.lang.String STATS_MANAGER = "stats";
field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
@@ -1069,6 +1072,7 @@ package android.content {
field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field public static final java.lang.String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
+ field public static final java.lang.String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
@@ -1204,6 +1208,7 @@ package android.content.pm {
method public void setAllocateAggressive(boolean);
method public void setAllowDowngrade(boolean);
method public void setDontKillApp(boolean);
+ method public void setEnableRollback();
method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallAsInstantApp(boolean);
method public void setInstallAsVirtualPreload();
@@ -1221,7 +1226,6 @@ package android.content.pm {
public abstract class PackageManager {
method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract boolean arePermissionsIndividuallyControlled();
- method public boolean canSuspendPackage(java.lang.String);
method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
method public android.content.pm.ApplicationInfo getApplicationInfoAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.dex.ArtManager getArtManager();
@@ -1235,6 +1239,7 @@ package android.content.pm {
method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public java.lang.String[] getUnsuspendablePackages(java.lang.String[]);
method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -1398,6 +1403,41 @@ package android.content.pm.permission {
}
+package android.content.rollback {
+
+ public final class PackageRollbackInfo implements android.os.Parcelable {
+ ctor public PackageRollbackInfo(java.lang.String, android.content.rollback.PackageRollbackInfo.PackageVersion, android.content.rollback.PackageRollbackInfo.PackageVersion);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
+ field public final android.content.rollback.PackageRollbackInfo.PackageVersion higherVersion;
+ field public final android.content.rollback.PackageRollbackInfo.PackageVersion lowerVersion;
+ field public final java.lang.String packageName;
+ }
+
+ public static class PackageRollbackInfo.PackageVersion {
+ ctor public PackageRollbackInfo.PackageVersion(long);
+ field public final long versionCode;
+ }
+
+ public final class RollbackInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
+ field public final android.content.rollback.PackageRollbackInfo targetPackage;
+ }
+
+ public final class RollbackManager {
+ method public void executeRollback(android.content.rollback.RollbackInfo, android.content.IntentSender);
+ method public void expireRollbackForPackage(java.lang.String);
+ method public android.content.rollback.RollbackInfo getAvailableRollback(java.lang.String);
+ method public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
+ method public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+ method public void reloadPersistedData();
+ }
+
+}
+
package android.hardware {
public final class Sensor {
@@ -1472,8 +1512,6 @@ package android.hardware.display {
public final class BrightnessConfiguration implements android.os.Parcelable {
method public int describeContents();
- method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
- method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String);
method public android.util.Pair<float[], float[]> getCurve();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
@@ -1481,22 +1519,10 @@ package android.hardware.display {
public static class BrightnessConfiguration.Builder {
ctor public BrightnessConfiguration.Builder(float[], float[]);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
- method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection);
method public android.hardware.display.BrightnessConfiguration build();
- method public int getMaxCorrectionsByCategory();
- method public int getMaxCorrectionsByPackageName();
method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
}
- public final class BrightnessCorrection implements android.os.Parcelable {
- method public float apply(float);
- method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
- }
-
public final class DisplayManager {
method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
@@ -3000,7 +3026,8 @@ package android.media {
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
- field public static final int FLAG_FROM_KEY = 4096; // 0x1000
+ field public static final int FLAG_FROM_KEY = 65536; // 0x10000
+ field public static final int SUCCESS = 0; // 0x0
}
public static abstract class AudioManager.AudioServerStateCallback {
@@ -3117,8 +3144,10 @@ package android.media.audiopolicy {
method public int detachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
method public int getFocusDuckingBehavior();
method public int getStatus();
+ method public int removeUidDeviceAffinity(int);
method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setRegistration(java.lang.String);
+ method public int setUidDeviceAffinity(int, java.util.List<android.media.AudioDeviceInfo>);
method public java.lang.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
@@ -3629,6 +3658,26 @@ package android.net {
package android.net.wifi {
+ public abstract class DppStatusCallback {
+ ctor public DppStatusCallback();
+ method public abstract void onConfiguratorSuccess(int);
+ method public abstract void onEnrolleeSuccess(int);
+ method public abstract void onFailure(int);
+ method public abstract void onProgress(int);
+ field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
+ field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+ field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+ field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+ field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+ field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+ field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+ field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+ field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+ field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+ field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+ field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+ }
+
public deprecated class RttManager {
method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
@@ -3858,7 +3907,10 @@ package android.net.wifi {
method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
method public void setDeviceMobilityState(int);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+ method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
+ method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
method public boolean startScan(android.os.WorkSource);
+ method public void stopDppSession();
method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -3868,6 +3920,8 @@ package android.net.wifi {
field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+ field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
+ field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
@@ -4534,6 +4588,7 @@ package android.os.storage {
method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException;
method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException;
+ method public static boolean hasIsolatedStorage();
field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
}
@@ -4541,6 +4596,16 @@ package android.os.storage {
package android.permission {
+ public abstract class PermissionControllerService extends android.app.Service {
+ ctor public PermissionControllerService();
+ method public final void attachBaseContext(android.content.Context);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
+ method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+ method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
+ }
+
public final class PermissionManager {
method public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
}
@@ -4561,16 +4626,6 @@ package android.permission {
field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionPresentationInfo> CREATOR;
}
- public abstract class RuntimePermissionPresenterService extends android.app.Service {
- ctor public RuntimePermissionPresenterService();
- method public final void attachBaseContext(android.content.Context);
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
- method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
- method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
- field public static final java.lang.String SERVICE_INTERFACE = "android.permission.RuntimePermissionPresenterService";
- }
-
}
package android.permissionpresenterservice {
@@ -6700,6 +6755,7 @@ package android.telephony.ims {
field public static final int DIALSTRING_SS_CONF = 1; // 0x1
field public static final int DIALSTRING_USSD = 2; // 0x2
field public static final java.lang.String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+ field public static final java.lang.String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
field public static final java.lang.String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
field public static final java.lang.String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final java.lang.String EXTRA_CNA = "cna";
@@ -7868,6 +7924,7 @@ package android.webkit {
method public void callDrawGlFunction(android.graphics.Canvas, long, java.lang.Runnable);
method public boolean canInvokeDrawGlFunctor(android.view.View);
method public void detachDrawGlFunctor(android.view.View, long);
+ method public void drawWebViewFunctor(android.graphics.Canvas, int);
method public android.app.Application getApplication();
method public java.lang.String getDataDirectorySuffix();
method public java.lang.String getErrorString(android.content.Context, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 71a06f11b692..1401cbb4211e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -72,6 +72,7 @@ package android.app {
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
method public void resizeStack(int, android.graphics.Rect, boolean);
method public void resizeTask(int, android.graphics.Rect);
+ method public void setDisplayToSingleTaskInstance(int);
method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
method public void startSystemLockTaskMode(int);
@@ -1108,6 +1109,20 @@ package android.service.autofill {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
+ public final class CompositeUserData implements android.os.Parcelable {
+ ctor public CompositeUserData(android.service.autofill.UserData, android.service.autofill.UserData);
+ method public int describeContents();
+ method public java.lang.String[] getCategoryIds();
+ method public android.os.Bundle getDefaultFieldClassificationArgs();
+ method public java.lang.String getFieldClassificationAlgorithm();
+ method public java.lang.String getFieldClassificationAlgorithmForCategory(java.lang.String);
+ method public android.util.ArrayMap<java.lang.String, java.lang.String> getFieldClassificationAlgorithms();
+ method public android.util.ArrayMap<java.lang.String, android.os.Bundle> getFieldClassificationArgs();
+ method public java.lang.String[] getValues();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CompositeUserData> CREATOR;
+ }
+
public final class CustomDescription implements android.os.Parcelable {
method public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions();
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 498eebce5999..04d4f9a6fd06 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -114,7 +114,7 @@ public:
virtual void shutdown() {}
};
- BootAnimation(sp<Callbacks> callbacks);
+ explicit BootAnimation(sp<Callbacks> callbacks);
sp<SurfaceComposerClient> session() const;
@@ -128,7 +128,7 @@ private:
class TimeCheckThread : public Thread {
public:
- TimeCheckThread(BootAnimation* bootAnimation);
+ explicit TimeCheckThread(BootAnimation* bootAnimation);
virtual ~TimeCheckThread();
private:
virtual status_t readyToRun();
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index fe7099b2f3ea..abe18ba8a415 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,6 +23,7 @@ cc_defaults {
],
tidy_flags: [
"-system-headers",
+ "-warnings-as-errors=*",
],
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index f0b751db5ae9..59b2aa6ac3d1 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -136,7 +136,7 @@ cc_defaults {
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power.stats@1.0",
- "android.hardware.thermal@1.0",
+ "android.hardware.thermal@2.0",
"libpackagelistparser",
"libsysutils",
"libcutils",
@@ -332,6 +332,8 @@ java_library {
"src/stats_log.proto",
"src/statsd_config.proto",
"src/atoms.proto",
+ "src/shell/shell_config.proto",
+ "src/shell/shell_data.proto",
],
static_libs: [
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f2a46636c382..3107b4dd7fce 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -360,7 +360,11 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
if (mShellSubscriber == nullptr) {
mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
}
- mShellSubscriber->startNewSubscription(in, out, resultReceiver);
+ int timeoutSec = -1;
+ if (argCount >= 2) {
+ timeoutSec = atoi(args[1].c_str());
+ }
+ mShellSubscriber->startNewSubscription(in, out, resultReceiver, timeoutSec);
return NO_ERROR;
}
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e5415430d82a..5c53a3a585f8 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2789,13 +2789,14 @@ message BatteryLevel {
* frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
*/
message Temperature {
- // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY.
+ // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY, BCL_.
optional android.os.TemperatureTypeEnum sensor_location = 1;
// The name of the temperature source. Eg. CPU0
optional string sensor_name = 2;
// Temperature in tenths of a degree C.
+ // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
optional int32 temperature_deci_celsius = 3;
}
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
index 33a17deabc5a..53709f14564d 100644
--- a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
@@ -17,7 +17,7 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include <android/hardware/thermal/1.0/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermal.h>
#include "external/ResourceThermalManagerPuller.h"
#include "external/StatsPuller.h"
@@ -31,10 +31,11 @@
using android::hardware::hidl_death_recipient;
using android::hardware::hidl_vec;
using android::hidl::base::V1_0::IBase;
-using android::hardware::thermal::V1_0::IThermal;
-using android::hardware::thermal::V1_0::Temperature;
-using android::hardware::thermal::V1_0::ThermalStatus;
-using android::hardware::thermal::V1_0::ThermalStatusCode;
+using ::android::hardware::thermal::V2_0::IThermal;
+using ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureType;
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
using android::hardware::Return;
using android::hardware::Void;
@@ -49,7 +50,7 @@ namespace os {
namespace statsd {
bool getThermalHalLocked();
-sp<android::hardware::thermal::V1_0::IThermal> gThermalHal = nullptr;
+sp<android::hardware::thermal::V2_0::IThermal> gThermalHal = nullptr;
std::mutex gThermalHalMutex;
struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
@@ -107,7 +108,7 @@ bool ResourceThermalManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* da
data->clear();
bool resultSuccess = true;
- Return<void> ret = gThermalHal->getTemperatures(
+ Return<void> ret = gThermalHal->getCurrentTemperatures(false, TemperatureType::SKIN,
[&](ThermalStatus status, const hidl_vec<Temperature>& temps) {
if (status.code != ThermalStatusCode::SUCCESS) {
ALOGE("Failed to get temperatures from ThermalHAL. Status: %d", status.code);
@@ -121,7 +122,7 @@ bool ResourceThermalManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* da
ptr->write((static_cast<int>(temps[i].type)));
ptr->write(temps[i].name);
// Convert the temperature to an int.
- int32_t temp = static_cast<int>(temps[i].currentValue * 10);
+ int32_t temp = static_cast<int>(temps[i].value * 10);
ptr->write(temp);
ptr->init();
data->push_back(ptr);
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 22883f3c205a..52d5ffc33317 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -30,7 +30,8 @@ namespace statsd {
const static int FIELD_ID_ATOM = 1;
-void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver) {
+void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver,
+ int timeoutSec) {
VLOG("start new shell subscription");
{
std::lock_guard<std::mutex> lock(mMutex);
@@ -50,11 +51,18 @@ void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver>
// Read config forever until EOF is reached. Clients may send multiple configs -- each new
// config replace the previous one.
readConfig(in);
+ VLOG("timeout : %d", timeoutSec);
// Now we have read an EOF we now wait for the semaphore until the client exits.
VLOG("Now wait for client to exit");
std::unique_lock<std::mutex> lk(mMutex);
- mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+
+ if (timeoutSec > 0) {
+ mShellDied.wait_for(lk, timeoutSec * 1s,
+ [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+ } else {
+ mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+ }
}
void ShellSubscriber::updateConfig(const ShellSubscription& config) {
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 5401f31ce68c..8e54a8b00091 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -65,7 +65,8 @@ public:
/**
* Start a new subscription.
*/
- void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver);
+ void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver,
+ int timeoutSec);
void binderDied(const wp<IBinder>& who);
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index a184f5672d65..73d1fd7850e9 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -83,7 +83,7 @@ void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
// mimic a binder thread that a shell subscriber runs on. it would block.
std::thread reader([&resultReceiver, &fds_config, &fds_data, &shellClient] {
- shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver);
+ shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver, -1);
});
reader.detach();
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index 0775afeaeda4..de818a8fd77d 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -54,7 +54,8 @@ public class TestDrive {
"AID_SYSTEM",
"AID_ROOT",
"AID_BLUETOOTH",
- "AID_LMKD"
+ "AID_LMKD",
+ "com.android.managedprovisioning"
};
private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt
index e69de29bb2d1..7840b186615f 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-greylist-max-p.txt
@@ -0,0 +1,75 @@
+Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
+Landroid/app/ISearchManager$Stub;-><init>()V
+Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IUiModeManager;
+Landroid/app/IUiModeManager;->disableCarMode(I)V
+Landroid/bluetooth/IBluetooth$Stub;-><init>()V
+Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V
+Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver;
+Landroid/content/IIntentSender$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentSender;
+Landroid/net/IConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
+Landroid/net/IConnectivityManager;->reportInetCondition(II)V
+Landroid/os/BatteryStats$Counter;-><init>()V
+Landroid/os/BatteryStats$HistoryItem;->clear()V
+Landroid/os/BatteryStats$HistoryItem;->next:Landroid/os/BatteryStats$HistoryItem;
+Landroid/os/BatteryStats$HistoryItem;->same(Landroid/os/BatteryStats$HistoryItem;)Z
+Landroid/os/BatteryStats$HistoryItem;->setTo(JBLandroid/os/BatteryStats$HistoryItem;)V
+Landroid/os/BatteryStats$HistoryItem;->setTo(Landroid/os/BatteryStats$HistoryItem;)V
+Landroid/os/BatteryStats$Timer;-><init>()V
+Landroid/os/BatteryStats$Uid$Pkg;-><init>()V
+Landroid/os/BatteryStats$Uid$Proc;-><init>()V
+Landroid/os/BatteryStats$Uid$Sensor;-><init>()V
+Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V
+Landroid/os/BatteryStats;-><init>()V
+Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
+Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J
+Landroid/os/CancellationSignal;->mCancelInProgress:Z
+Landroid/os/CancellationSignal;->mIsCanceled:Z
+Landroid/os/CancellationSignal;->mOnCancelListener:Landroid/os/CancellationSignal$OnCancelListener;
+Landroid/os/CancellationSignal;->mRemote:Landroid/os/ICancellationSignal;
+Landroid/os/CancellationSignal;->waitForCancelFinishedLocked()V
+Landroid/os/IPowerManager;->nap(J)V
+Landroid/os/Parcel;->mCreators:Ljava/util/HashMap;
+Landroid/os/PowerManager;->mHandler:Landroid/os/Handler;
+Landroid/os/Process;->sendSignalQuiet(II)V
+Landroid/os/Registrant;->getHandler()Landroid/os/Handler;
+Landroid/os/RegistrantList;->get(I)Ljava/lang/Object;
+Landroid/os/RemoteCallback;->mHandler:Landroid/os/Handler;
+Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener;
+Landroid/os/SystemProperties;->native_add_change_callback()V
+Landroid/os/SystemProperties;->native_get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+Landroid/os/SystemProperties;->native_get_boolean(Ljava/lang/String;Z)Z
+Landroid/os/SystemProperties;->native_get_int(Ljava/lang/String;I)I
+Landroid/os/SystemProperties;->native_set(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
+Landroid/os/WorkSource;->sGoneWork:Landroid/os/WorkSource;
+Landroid/os/WorkSource;->sNewbWork:Landroid/os/WorkSource;
+Landroid/os/WorkSource;->sTmpWorkSource:Landroid/os/WorkSource;
+Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
+Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
+Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
+Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
+Landroid/view/IWindowManager;->setInTouchMode(Z)V
+Landroid/view/IWindowManager;->showStrictModeViolation(Z)V
+Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I
+Lcom/android/internal/R$styleable;->AndroidManifestGrantUriPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestInstrumentation:[I
+Lcom/android/internal/R$styleable;->AndroidManifestOriginalPackage:[I
+Lcom/android/internal/R$styleable;->AndroidManifestPathPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestPermission:[I
+Lcom/android/internal/R$styleable;->AndroidManifestPermissionGroup:[I
+Lcom/android/internal/R$styleable;->AndroidManifestPermissionTree:[I
+Lcom/android/internal/R$styleable;->AndroidManifestProtectedBroadcast:[I
+Lcom/android/internal/R$styleable;->AndroidManifestSupportsScreens:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesConfiguration:[I
+Lcom/android/internal/R$styleable;->AndroidManifestUsesFeature:[I
+Lcom/android/internal/R$styleable;->CycleInterpolator:[I
+Lcom/android/internal/R$styleable;->LinearLayout:[I
+Lcom/android/internal/R$styleable;->MenuView:[I
+Lcom/android/internal/R$styleable;->Searchable:[I
+Lcom/android/internal/R$styleable;->SearchableActionKey:[I
+Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallForwardingChanged(Z)V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellLocation(Landroid/os/Bundle;)V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataActivity(I)V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyOtaspChanged(I)V
+Lcom/android/internal/view/BaseIWindow;-><init>()V
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 8f28ae175016..041fbfaff23d 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -173,7 +173,6 @@ Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V
Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
Landroid/app/IInputForwarder;->forwardEvent(Landroid/view/InputEvent;)Z
Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
-Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
Landroid/app/IInstrumentationWatcher;->instrumentationStatus(Landroid/content/ComponentName;ILandroid/os/Bundle;)V
Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/INotificationManager$Stub$Proxy;->areNotificationsEnabledForPackage(Ljava/lang/String;I)Z
@@ -191,7 +190,6 @@ Landroid/app/INotificationManager;->getZenModeConfig()Landroid/service/notificat
Landroid/app/IProcessObserver$Stub;-><init>()V
Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName;
Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName;
-Landroid/app/ISearchManager$Stub;-><init>()V
Landroid/app/ISearchManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/ISearchManager;
Landroid/app/ISearchManager;->getGlobalSearchActivity()Landroid/content/ComponentName;
Landroid/app/IServiceConnection$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -206,8 +204,6 @@ Landroid/app/IStopUserCallback;->userStopped(I)V
Landroid/app/ITransientNotification$Stub;-><init>()V
Landroid/app/ITransientNotification;->show(Landroid/os/IBinder;)V
Landroid/app/IUiModeManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/app/IUiModeManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IUiModeManager;
-Landroid/app/IUiModeManager;->disableCarMode(I)V
Landroid/app/IUserSwitchObserver$Stub;-><init>()V
Landroid/app/IWallpaperManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IWallpaperManager;
Landroid/app/IWallpaperManager;->getHeightHint(I)I
@@ -250,7 +246,6 @@ Landroid/app/usage/IUsageStatsManager;->setAppInactive(Ljava/lang/String;ZI)V
Landroid/app/UserSwitchObserver;-><init>()V
Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
-Landroid/bluetooth/IBluetooth$Stub;-><init>()V
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
Landroid/bluetooth/IBluetooth;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDevice;)Z
@@ -258,7 +253,6 @@ Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->isEnabled()Z
Landroid/bluetooth/IBluetooth;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V
-Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V
Landroid/bluetooth/IBluetoothA2dp$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothA2dp;
Landroid/bluetooth/IBluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
Landroid/bluetooth/IBluetoothA2dp;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
@@ -307,9 +301,7 @@ Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
Landroid/content/IIntentReceiver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IIntentReceiver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/content/IIntentReceiver$Stub;-><init>()V
-Landroid/content/IIntentReceiver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentReceiver;
Landroid/content/IIntentReceiver;->performReceive(Landroid/content/Intent;ILjava/lang/String;Landroid/os/Bundle;ZZI)V
-Landroid/content/IIntentSender$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IIntentSender;
Landroid/content/IOnPrimaryClipChangedListener$Stub;-><init>()V
Landroid/content/IOnPrimaryClipChangedListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IOnPrimaryClipChangedListener;
Landroid/content/IRestrictionsManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IRestrictionsManager;
@@ -554,13 +546,11 @@ Landroid/net/IConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkIn
Landroid/net/IConnectivityManager;->getAllNetworkInfo()[Landroid/net/NetworkInfo;
Landroid/net/IConnectivityManager;->getAllNetworkState()[Landroid/net/NetworkState;
Landroid/net/IConnectivityManager;->getLastTetherError(Ljava/lang/String;)I
-Landroid/net/IConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
Landroid/net/IConnectivityManager;->getTetherableIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetherableUsbRegexs()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetherableWifiRegexs()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
-Landroid/net/IConnectivityManager;->reportInetCondition(II)V
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd;
Landroid/net/INetd;->interfaceAddAddress(Ljava/lang/String;Ljava/lang/String;I)V
@@ -634,7 +624,6 @@ Landroid/os/BatteryManager;->EXTRA_CHARGE_COUNTER:Ljava/lang/String;
Landroid/os/BatteryManager;->EXTRA_INVALID_CHARGER:Ljava/lang/String;
Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_CURRENT:Ljava/lang/String;
Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_VOLTAGE:Ljava/lang/String;
-Landroid/os/BatteryStats$Counter;-><init>()V
Landroid/os/BatteryStats$Counter;->getCountLocked(I)I
Landroid/os/BatteryStats$HistoryItem;-><init>()V
Landroid/os/BatteryStats$HistoryItem;->batteryHealth:B
@@ -642,41 +631,31 @@ Landroid/os/BatteryStats$HistoryItem;->batteryLevel:B
Landroid/os/BatteryStats$HistoryItem;->batteryPlugType:B
Landroid/os/BatteryStats$HistoryItem;->batteryStatus:B
Landroid/os/BatteryStats$HistoryItem;->batteryVoltage:C
-Landroid/os/BatteryStats$HistoryItem;->clear()V
Landroid/os/BatteryStats$HistoryItem;->cmd:B
Landroid/os/BatteryStats$HistoryItem;->CMD_UPDATE:B
-Landroid/os/BatteryStats$HistoryItem;->next:Landroid/os/BatteryStats$HistoryItem;
-Landroid/os/BatteryStats$HistoryItem;->same(Landroid/os/BatteryStats$HistoryItem;)Z
-Landroid/os/BatteryStats$HistoryItem;->setTo(JBLandroid/os/BatteryStats$HistoryItem;)V
-Landroid/os/BatteryStats$HistoryItem;->setTo(Landroid/os/BatteryStats$HistoryItem;)V
Landroid/os/BatteryStats$HistoryItem;->states2:I
Landroid/os/BatteryStats$HistoryItem;->states:I
Landroid/os/BatteryStats$HistoryItem;->time:J
-Landroid/os/BatteryStats$Timer;-><init>()V
Landroid/os/BatteryStats$Timer;->getCountLocked(I)I
Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I
Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStarts(I)I
Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStartTime(JI)J
-Landroid/os/BatteryStats$Uid$Pkg;-><init>()V
Landroid/os/BatteryStats$Uid$Pkg;->getServiceStats()Landroid/util/ArrayMap;
Landroid/os/BatteryStats$Uid$Pkg;->getWakeupAlarmStats()Landroid/util/ArrayMap;
Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;-><init>()V
Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->overTime:J
Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->type:I
Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->usedTime:J
-Landroid/os/BatteryStats$Uid$Proc;-><init>()V
Landroid/os/BatteryStats$Uid$Proc;->countExcessivePowers()I
Landroid/os/BatteryStats$Uid$Proc;->getExcessivePower(I)Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;
Landroid/os/BatteryStats$Uid$Proc;->getForegroundTime(I)J
Landroid/os/BatteryStats$Uid$Proc;->getStarts(I)I
Landroid/os/BatteryStats$Uid$Proc;->getSystemTime(I)J
Landroid/os/BatteryStats$Uid$Proc;->getUserTime(I)J
-Landroid/os/BatteryStats$Uid$Sensor;-><init>()V
Landroid/os/BatteryStats$Uid$Sensor;->getHandle()I
Landroid/os/BatteryStats$Uid$Sensor;->getSensorTime()Landroid/os/BatteryStats$Timer;
Landroid/os/BatteryStats$Uid$Sensor;->GPS:I
-Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V
Landroid/os/BatteryStats$Uid$Wakelock;->getWakeTime(I)Landroid/os/BatteryStats$Timer;
Landroid/os/BatteryStats$Uid;-><init>()V
Landroid/os/BatteryStats$Uid;->getAudioTurnedOnTimer()Landroid/os/BatteryStats$Timer;
@@ -693,7 +672,6 @@ Landroid/os/BatteryStats$Uid;->getWifiBatchedScanTime(IJI)J
Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J
Landroid/os/BatteryStats$Uid;->getWifiRunningTime(JI)J
Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J
-Landroid/os/BatteryStats;-><init>()V
Landroid/os/BatteryStats;->computeBatteryRealtime(JI)J
Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J
Landroid/os/BatteryStats;->computeBatteryUptime(JI)J
@@ -701,8 +679,6 @@ Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J
Landroid/os/BatteryStats;->dumpLine(Ljava/io/PrintWriter;ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/os/BatteryStats;->getBatteryUptime(J)J
Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
-Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
-Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J
Landroid/os/BatteryStats;->getNextHistoryLocked(Landroid/os/BatteryStats$HistoryItem;)Z
Landroid/os/BatteryStats;->getPhoneOnTime(JI)J
Landroid/os/BatteryStats;->getPhoneSignalStrengthTime(IJI)J
@@ -733,11 +709,6 @@ Landroid/os/Bundle;->getSize()I
Landroid/os/Bundle;->putIBinder(Ljava/lang/String;Landroid/os/IBinder;)V
Landroid/os/Bundle;->putParcelableList(Ljava/lang/String;Ljava/util/List;)V
Landroid/os/Bundle;->setDefusable(Landroid/os/Bundle;Z)Landroid/os/Bundle;
-Landroid/os/CancellationSignal;->mCancelInProgress:Z
-Landroid/os/CancellationSignal;->mIsCanceled:Z
-Landroid/os/CancellationSignal;->mOnCancelListener:Landroid/os/CancellationSignal$OnCancelListener;
-Landroid/os/CancellationSignal;->mRemote:Landroid/os/ICancellationSignal;
-Landroid/os/CancellationSignal;->waitForCancelFinishedLocked()V
Landroid/os/Debug$MemoryInfo;->dalvikPrivateClean:I
Landroid/os/Debug$MemoryInfo;->dalvikRss:I
Landroid/os/Debug$MemoryInfo;->dalvikSharedClean:I
@@ -864,7 +835,6 @@ Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
Landroid/os/IPowerManager;->goToSleep(JII)V
Landroid/os/IPowerManager;->isInteractive()Z
-Landroid/os/IPowerManager;->nap(J)V
Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V
Landroid/os/IPowerManager;->releaseWakeLock(Landroid/os/IBinder;I)V
Landroid/os/IPowerManager;->userActivity(JII)V
@@ -912,7 +882,6 @@ Landroid/os/MessageQueue;->next()Landroid/os/Message;
Landroid/os/Parcel$ReadWriteHelper;-><init>()V
Landroid/os/Parcel;->getGlobalAllocCount()J
Landroid/os/Parcel;->getGlobalAllocSize()J
-Landroid/os/Parcel;->mCreators:Ljava/util/HashMap;
Landroid/os/Parcel;->mNativePtr:J
Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
Landroid/os/Parcel;->readArraySet(Ljava/lang/ClassLoader;)Landroid/util/ArraySet;
@@ -953,7 +922,6 @@ Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
Landroid/os/PowerManager;->goToSleep(JII)V
Landroid/os/PowerManager;->GO_TO_SLEEP_REASON_TIMEOUT:I
Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
-Landroid/os/PowerManager;->mHandler:Landroid/os/Handler;
Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
@@ -985,7 +953,6 @@ Landroid/os/Process;->PROC_ZERO_TERM:I
Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z
Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V
Landroid/os/Process;->ROOT_UID:I
-Landroid/os/Process;->sendSignalQuiet(II)V
Landroid/os/Process;->setArgV0(Ljava/lang/String;)V
Landroid/os/Process;->setProcessGroup(II)V
Landroid/os/Process;->SHELL_UID:I
@@ -994,7 +961,6 @@ Landroid/os/Process;->WIFI_UID:I
Landroid/os/RecoverySystem;->verifyPackageCompatibility(Ljava/io/InputStream;)Z
Landroid/os/Registrant;-><init>(Landroid/os/Handler;ILjava/lang/Object;)V
Landroid/os/Registrant;->clear()V
-Landroid/os/Registrant;->getHandler()Landroid/os/Handler;
Landroid/os/Registrant;->messageForRegistrant()Landroid/os/Message;
Landroid/os/Registrant;->notifyRegistrant()V
Landroid/os/Registrant;->notifyRegistrant(Landroid/os/AsyncResult;)V
@@ -1003,14 +969,12 @@ Landroid/os/RegistrantList;-><init>()V
Landroid/os/RegistrantList;->add(Landroid/os/Handler;ILjava/lang/Object;)V
Landroid/os/RegistrantList;->add(Landroid/os/Registrant;)V
Landroid/os/RegistrantList;->addUnique(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/RegistrantList;->get(I)Ljava/lang/Object;
Landroid/os/RegistrantList;->notifyRegistrants()V
Landroid/os/RegistrantList;->notifyRegistrants(Landroid/os/AsyncResult;)V
Landroid/os/RegistrantList;->notifyResult(Ljava/lang/Object;)V
Landroid/os/RegistrantList;->remove(Landroid/os/Handler;)V
Landroid/os/RegistrantList;->removeCleared()V
Landroid/os/RegistrantList;->size()I
-Landroid/os/RemoteCallback;->mHandler:Landroid/os/Handler;
Landroid/os/RemoteCallbackList;->mCallbacks:Landroid/util/ArrayMap;
Landroid/os/RemoteException;->rethrowFromSystemServer()Ljava/lang/RuntimeException;
Landroid/os/SELinux;->checkSELinuxAccess(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
@@ -1039,7 +1003,6 @@ Landroid/os/SharedMemory;->getFd()I
Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
Landroid/os/StatFs;->mStat:Landroid/system/StructStatVfs;
Landroid/os/storage/IObbActionListener$Stub;-><init>()V
-Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener;
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/os/storage/StorageEventListener;-><init>()V
@@ -1062,13 +1025,8 @@ Landroid/os/SystemClock;->currentThreadTimeMicro()J
Landroid/os/SystemClock;->currentTimeMicro()J
Landroid/os/SystemProperties;-><init>()V
Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
-Landroid/os/SystemProperties;->native_add_change_callback()V
Landroid/os/SystemProperties;->native_get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->native_get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->native_get_boolean(Ljava/lang/String;Z)Z
-Landroid/os/SystemProperties;->native_get_int(Ljava/lang/String;I)I
Landroid/os/SystemProperties;->native_get_long(Ljava/lang/String;J)J
-Landroid/os/SystemProperties;->native_set(Ljava/lang/String;Ljava/lang/String;)V
Landroid/os/SystemProperties;->PROP_NAME_MAX:I
Landroid/os/SystemProperties;->reportSyspropChanged()V
Landroid/os/SystemProperties;->sChangeCallbacks:Ljava/util/ArrayList;
@@ -1108,7 +1066,6 @@ Landroid/os/UserHandle;->AID_ROOT:I
Landroid/os/UserHandle;->AID_SHARED_GID_START:I
Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle;
Landroid/os/UserHandle;->ERR_GID:I
-Landroid/os/UserHandle;->formatUid(Ljava/io/PrintWriter;I)V
Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I
Landroid/os/UserHandle;->getCallingUserId()I
Landroid/os/UserHandle;->getUid(II)I
@@ -1169,10 +1126,6 @@ Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V
Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
Landroid/os/WorkSource;->mNum:I
Landroid/os/WorkSource;->mUids:[I
-Landroid/os/WorkSource;->sGoneWork:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->sNewbWork:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->sTmpWorkSource:Landroid/os/WorkSource;
-Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/String;)V
Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/Throwable;)V
Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference;
@@ -1465,8 +1418,6 @@ Landroid/security/keystore/IKeystoreService;->is_hardware_backed(Ljava/lang/Stri
Landroid/security/keystore/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String;
Landroid/security/keystore/IKeystoreService;->reset()I
Landroid/security/keystore/IKeystoreService;->ungrant(Ljava/lang/String;I)I
-Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
-Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
Landroid/service/dreams/IDreamManager;->awaken()V
Landroid/service/dreams/IDreamManager;->dream()V
@@ -1503,7 +1454,6 @@ Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBin
Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
-Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
Landroid/telephony/ims/compat/ImsService;-><init>()V
Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V
@@ -1606,11 +1556,9 @@ Landroid/view/IWindowManager;->registerDockedStackListener(Landroid/view/IDocked
Landroid/view/IWindowManager;->removeRotationWatcher(Landroid/view/IRotationWatcher;)V
Landroid/view/IWindowManager;->setAnimationScale(IF)V
Landroid/view/IWindowManager;->setAnimationScales([F)V
-Landroid/view/IWindowManager;->setInTouchMode(Z)V
Landroid/view/IWindowManager;->setNavBarVirtualKeyHapticFeedbackEnabled(Z)V
Landroid/view/IWindowManager;->setShelfHeight(ZI)V
Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
-Landroid/view/IWindowManager;->showStrictModeViolation(Z)V
Landroid/view/IWindowManager;->thawRotation()V
Landroid/view/IWindowSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowSession;
Landroid/view/IWindowSession;->finishDrawing(Landroid/view/IWindow;)V
@@ -2106,7 +2054,6 @@ Lcom/android/internal/R$styleable;->AlertDialog:[I
Lcom/android/internal/R$styleable;->AnalogClock:[I
Lcom/android/internal/R$styleable;->AndroidManifest:[I
Lcom/android/internal/R$styleable;->AndroidManifestActivity:[I
-Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I
Lcom/android/internal/R$styleable;->AndroidManifestActivity_allowTaskReparenting:I
Lcom/android/internal/R$styleable;->AndroidManifestActivity_configChanges:I
Lcom/android/internal/R$styleable;->AndroidManifestActivity_description:I
@@ -2140,21 +2087,13 @@ Lcom/android/internal/R$styleable;->AndroidManifestApplication_supportsRtl:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_theme:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_uiOptions:I
Lcom/android/internal/R$styleable;->AndroidManifestData:[I
-Lcom/android/internal/R$styleable;->AndroidManifestGrantUriPermission:[I
-Lcom/android/internal/R$styleable;->AndroidManifestInstrumentation:[I
Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter:[I
Lcom/android/internal/R$styleable;->AndroidManifestIntentFilter_priority:I
Lcom/android/internal/R$styleable;->AndroidManifestMetaData:[I
Lcom/android/internal/R$styleable;->AndroidManifestMetaData_name:I
Lcom/android/internal/R$styleable;->AndroidManifestMetaData_resource:I
Lcom/android/internal/R$styleable;->AndroidManifestMetaData_value:I
-Lcom/android/internal/R$styleable;->AndroidManifestOriginalPackage:[I
Lcom/android/internal/R$styleable;->AndroidManifestPackageVerifier:[I
-Lcom/android/internal/R$styleable;->AndroidManifestPathPermission:[I
-Lcom/android/internal/R$styleable;->AndroidManifestPermission:[I
-Lcom/android/internal/R$styleable;->AndroidManifestPermissionGroup:[I
-Lcom/android/internal/R$styleable;->AndroidManifestPermissionTree:[I
-Lcom/android/internal/R$styleable;->AndroidManifestProtectedBroadcast:[I
Lcom/android/internal/R$styleable;->AndroidManifestProvider:[I
Lcom/android/internal/R$styleable;->AndroidManifestService:[I
Lcom/android/internal/R$styleable;->AndroidManifestService_enabled:I
@@ -2162,9 +2101,6 @@ Lcom/android/internal/R$styleable;->AndroidManifestService_exported:I
Lcom/android/internal/R$styleable;->AndroidManifestService_name:I
Lcom/android/internal/R$styleable;->AndroidManifestService_permission:I
Lcom/android/internal/R$styleable;->AndroidManifestService_process:I
-Lcom/android/internal/R$styleable;->AndroidManifestSupportsScreens:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesConfiguration:[I
-Lcom/android/internal/R$styleable;->AndroidManifestUsesFeature:[I
Lcom/android/internal/R$styleable;->AndroidManifestUsesLibrary:[I
Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission:[I
Lcom/android/internal/R$styleable;->AndroidManifestUsesPermission_name:I
@@ -2187,7 +2123,6 @@ Lcom/android/internal/R$styleable;->CompoundButton:[I
Lcom/android/internal/R$styleable;->CompoundButton_button:I
Lcom/android/internal/R$styleable;->CompoundButton_checked:I
Lcom/android/internal/R$styleable;->ContactsDataKind:[I
-Lcom/android/internal/R$styleable;->CycleInterpolator:[I
Lcom/android/internal/R$styleable;->DatePicker:[I
Lcom/android/internal/R$styleable;->DialogPreference:[I
Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
@@ -2207,7 +2142,6 @@ Lcom/android/internal/R$styleable;->Keyboard:[I
Lcom/android/internal/R$styleable;->KeyboardView:[I
Lcom/android/internal/R$styleable;->Keyboard_Key:[I
Lcom/android/internal/R$styleable;->Keyboard_Row:[I
-Lcom/android/internal/R$styleable;->LinearLayout:[I
Lcom/android/internal/R$styleable;->ListPreference:[I
Lcom/android/internal/R$styleable;->ListPreference_entries:I
Lcom/android/internal/R$styleable;->ListView:[I
@@ -2222,7 +2156,6 @@ Lcom/android/internal/R$styleable;->MapView:[I
Lcom/android/internal/R$styleable;->MapView_apiKey:I
Lcom/android/internal/R$styleable;->MenuGroup:[I
Lcom/android/internal/R$styleable;->MenuItem:[I
-Lcom/android/internal/R$styleable;->MenuView:[I
Lcom/android/internal/R$styleable;->NumberPicker:[I
Lcom/android/internal/R$styleable;->PopupWindow:[I
Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
@@ -2249,8 +2182,6 @@ Lcom/android/internal/R$styleable;->QuickContactBadge:[I
Lcom/android/internal/R$styleable;->RingtonePreference:[I
Lcom/android/internal/R$styleable;->ScrollView:[I
Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
-Lcom/android/internal/R$styleable;->Searchable:[I
-Lcom/android/internal/R$styleable;->SearchableActionKey:[I
Lcom/android/internal/R$styleable;->SelectionModeDrawables:[I
Lcom/android/internal/R$styleable;->Switch:[I
Lcom/android/internal/R$styleable;->SwitchPreference:[I
@@ -2906,8 +2837,6 @@ Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:
Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver;
Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State;
Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyDataConnection(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyOffApnsOfAvailability(Ljava/lang/String;)V
Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
@@ -3311,7 +3240,6 @@ Lcom/android/internal/telephony/IntRangeManager;->mRanges:Ljava/util/ArrayList;
Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/IPhoneSubInfo$Stub;-><init>()V
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/telephony/IPhoneSubInfo;->getIccSerialNumber(Ljava/lang/String;)Ljava/lang/String;
@@ -3358,13 +3286,9 @@ Lcom/android/internal/telephony/ITelephony;->updateServiceLocation()V
Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry;
Lcom/android/internal/telephony/ITelephonyRegistry;->listen(Ljava/lang/String;Lcom/android/internal/telephony/IPhoneStateListener;IZ)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallForwardingChanged(Z)V
Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallState(ILjava/lang/String;)V
Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellInfo(Ljava/util/List;)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellLocation(Landroid/os/Bundle;)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataActivity(I)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataConnectionFailed(Ljava/lang/String;Ljava/lang/String;)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyOtaspChanged(I)V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataConnectionFailed(Ljava/lang/String;)V
Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IWapPushManager;
Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
@@ -4138,7 +4062,6 @@ Lcom/android/internal/view/ActionBarPolicy;->getTabContainerHeight()I
Lcom/android/internal/view/ActionBarPolicy;->hasEmbeddedTabs()Z
Lcom/android/internal/view/ActionBarPolicy;->mContext:Landroid/content/Context;
Lcom/android/internal/view/ActionBarPolicy;->showsOverflowMenuButton()Z
-Lcom/android/internal/view/BaseIWindow;-><init>()V
Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 997ed25a42c6..e86fa8935469 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -19,6 +19,7 @@ package android.accessibilityservice;
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -794,7 +795,7 @@ public class AccessibilityServiceInfo implements Parcelable {
*
* @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
*/
- public void setNonInteractiveUiTimeoutMillis(int timeout) {
+ public void setNonInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
mNonInteractiveUiTimeout = timeout;
}
@@ -821,7 +822,7 @@ public class AccessibilityServiceInfo implements Parcelable {
*
* @see android.R.styleable#AccessibilityService_interactiveUiTimeout
*/
- public void setInteractiveUiTimeoutMillis(int timeout) {
+ public void setInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
mInteractiveUiTimeout = timeout;
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 579144bbce73..26c2c0cfdd5d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2226,12 +2226,12 @@ public class AccountManager {
}
private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final IAccountManagerResponse mResponse;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Handler mHandler;
final AccountManagerCallback<Bundle> mCallback;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Activity mActivity;
public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
super(new Callable<Bundle>() {
@@ -2556,13 +2556,13 @@ public class AccountManager {
}
volatile AccountManagerFuture<Bundle> mFuture = null;
final String mAccountType;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final String mAuthTokenType;
final String[] mFeatures;
final Bundle mAddAccountOptions;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Bundle mLoginOptions;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final AccountManagerCallback<Bundle> mMyCallback;
private volatile int mNumAccounts = 0;
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
index 6875867108de..2360cec5bde8 100644
--- a/core/java/android/accounts/AuthenticatorDescription.java
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -17,6 +17,7 @@
package android.accounts;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcelable;
import android.os.Parcel;
@@ -77,7 +78,7 @@ public class AuthenticatorDescription implements Parcelable {
return new AuthenticatorDescription(type);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private AuthenticatorDescription(String type) {
this.type = type;
this.packageName = null;
@@ -88,7 +89,7 @@ public class AuthenticatorDescription implements Parcelable {
this.customTokens = false;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private AuthenticatorDescription(Parcel source) {
this.type = source.readString();
this.packageName = source.readString();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3561f71b23af..5b8261e38f1e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -848,7 +848,7 @@ public class Activity extends ContextThemeWrapper
@UnsupportedAppUsage
/*package*/ boolean mWindowAdded = false;
/*package*/ boolean mVisibleFromServer = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
/*package*/ boolean mVisibleFromClient = true;
/*package*/ ActionBar mActionBar = null;
private boolean mEnableDefaultActionBarUp;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index b42d53ad10f6..0b509169010c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -73,6 +73,12 @@ public abstract class ActivityManagerInternal {
IBinder whitelistToken, long duration);
/**
+ * Allows for a {@link PendingIntent} to be whitelisted to start activities from background.
+ */
+ public abstract void setPendingIntentAllowBgActivityStarts(
+ IIntentSender target, IBinder whitelistToken, int flags);
+
+ /**
* Allow DeviceIdleController to tell us about what apps are whitelisted.
*/
public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids);
@@ -250,7 +256,7 @@ public abstract class ActivityManagerInternal {
public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent,
String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
- boolean sticky, int userId);
+ boolean sticky, int userId, boolean allowBackgroundActivityStarts);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage, int userId)
throws TransactionTooLargeException;
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 4d8c8563ad7c..7eab5dba5f82 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -430,4 +430,17 @@ public class ActivityTaskManager {
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Makes the display with the given id a single task instance display. I.e the display can only
+ * contain one task.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void setDisplayToSingleTaskInstance(int displayId) {
+ try {
+ getService().setDisplayToSingleTaskInstance(displayId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 497e193c38ec..8faf08a77355 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3497,7 +3497,7 @@ public final class ActivityThread extends ClientTransactionHandler {
return sCurrentBroadcastIntent.get();
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void handleReceiver(ReceiverData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 680fed80d029..0b5776e89524 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -83,6 +83,9 @@ public class ActivityView extends ViewGroup {
private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
private Surface mTmpSurface = new Surface();
+ /** The ActivityView is only allowed to contain one task. */
+ private final boolean mSingleTaskInstance;
+
@UnsupportedAppUsage
public ActivityView(Context context) {
this(context, null /* attrs */);
@@ -93,7 +96,13 @@ public class ActivityView extends ViewGroup {
}
public ActivityView(Context context, AttributeSet attrs, int defStyle) {
+ this(context, attrs, defStyle, false /*singleTaskInstance*/);
+ }
+
+ public ActivityView(
+ Context context, AttributeSet attrs, int defStyle, boolean singleTaskInstance) {
super(context, attrs, defStyle);
+ mSingleTaskInstance = singleTaskInstance;
mActivityTaskManager = ActivityTaskManager.getService();
mSurfaceView = new SurfaceView(context);
@@ -379,6 +388,9 @@ public class ActivityView extends ViewGroup {
try {
wm.reparentDisplayContent(displayId, mRootSurfaceControl.getHandle());
wm.dontOverrideDisplayInfo(displayId);
+ if (mSingleTaskInstance) {
+ mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);
+ }
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 17529a6dacf0..94983e1c3672 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2299,9 +2299,9 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public boolean canSuspendPackage(String packageName) {
+ public String[] getUnsuspendablePackages(String[] packageNames) {
try {
- return mPM.canSuspendPackageForUser(packageName, mContext.getUserId());
+ return mPM.getUnsuspendablePackagesForUser(packageNames, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6bcfb2e8fe9e..4bd935c0e924 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -130,7 +130,7 @@ public class Dialog implements DialogInterface, Window.Callback,
private boolean mShowing = false;
private boolean mCanceled = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Handler mHandler = new Handler();
private static final int DISMISS = 0x43;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index dbc4e34decf4..4f121aa35f7c 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -390,7 +390,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
ViewGroup mContainer;
// The View generated for this fragment.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
View mView;
// Whether this fragment should defer starting until after other fragments
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index f549e1890b5e..dd87dc330b65 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -452,4 +452,10 @@ interface IActivityTaskManager {
* Clears launch params for given packages.
*/
void clearLaunchParamsForPackages(in List<String> packageNames);
+
+ /**
+ * Makes the display with the given id a single task instance display. I.e the display can only
+ * contain one task.
+ */
+ void setDisplayToSingleTaskInstance(int displayId);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index d7c7f3c8a937..dda5569a26b3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.input.InputManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -2029,7 +2030,7 @@ public class Instrumentation {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
return;
diff --git a/core/java/android/app/ProgressDialog.java b/core/java/android/app/ProgressDialog.java
index 1b10fd7cf86d..3193eb89ac80 100644
--- a/core/java/android/app/ProgressDialog.java
+++ b/core/java/android/app/ProgressDialog.java
@@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -64,7 +65,7 @@ public class ProgressDialog extends AlertDialog {
*/
public static final int STYLE_HORIZONTAL = 1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private ProgressBar mProgress;
@UnsupportedAppUsage
private TextView mMessageView;
diff --git a/core/java/android/app/ResultInfo.java b/core/java/android/app/ResultInfo.java
index 4335488777ba..d916c94ab6c5 100644
--- a/core/java/android/app/ResultInfo.java
+++ b/core/java/android/app/ResultInfo.java
@@ -18,6 +18,7 @@ package android.app;
import android.annotation.UnsupportedAppUsage;
import android.content.Intent;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,7 +66,7 @@ public class ResultInfo implements Parcelable {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final Parcelable.Creator<ResultInfo> CREATOR
= new Parcelable.Creator<ResultInfo>() {
public ResultInfo createFromParcel(Parcel in) {
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index bf3d885cd9c9..bbe5b8b51a35 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -69,6 +69,22 @@ public class StatusBarManager {
| DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
| DISABLE_SEARCH;
+ @IntDef(flag = true, prefix = {"DISABLE_"}, value = {
+ DISABLE_NONE,
+ DISABLE_EXPAND,
+ DISABLE_NOTIFICATION_ICONS,
+ DISABLE_NOTIFICATION_ALERTS,
+ DISABLE_NOTIFICATION_TICKER,
+ DISABLE_SYSTEM_INFO,
+ DISABLE_HOME,
+ DISABLE_RECENT,
+ DISABLE_BACK,
+ DISABLE_CLOCK,
+ DISABLE_SEARCH
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DisableFlags {}
+
/**
* Flag to disable quick settings.
*
@@ -104,10 +120,25 @@ public class StatusBarManager {
public static final int WINDOW_STATUS_BAR = 1;
public static final int WINDOW_NAVIGATION_BAR = 2;
+ @IntDef(flag = true, prefix = { "WINDOW_" }, value = {
+ WINDOW_STATUS_BAR,
+ WINDOW_NAVIGATION_BAR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WindowType {}
+
public static final int WINDOW_STATE_SHOWING = 0;
public static final int WINDOW_STATE_HIDING = 1;
public static final int WINDOW_STATE_HIDDEN = 2;
+ @IntDef(flag = true, prefix = { "WINDOW_STATE_" }, value = {
+ WINDOW_STATE_SHOWING,
+ WINDOW_STATE_HIDING,
+ WINDOW_STATE_HIDDEN
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WindowVisibleState {}
+
public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fb72f06e541f..9ddf4bd0870c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -49,6 +49,8 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.res.Resources;
+import android.content.rollback.IRollbackManager;
+import android.content.rollback.RollbackManager;
import android.debug.AdbManager;
import android.debug.IAdbManager;
import android.hardware.ConsumerIrManager;
@@ -142,6 +144,7 @@ import android.os.UserManager;
import android.os.Vibrator;
import android.os.health.SystemHealthManager;
import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.print.IPrintManager;
import android.print.PrintManager;
@@ -1162,6 +1165,13 @@ final class SystemServiceRegistry {
return new PermissionManager(ctx.getOuterContext());
}});
+ registerService(Context.PERMISSION_CONTROLLER_SERVICE, PermissionControllerManager.class,
+ new CachedServiceFetcher<PermissionControllerManager>() {
+ @Override
+ public PermissionControllerManager createService(ContextImpl ctx) {
+ return new PermissionControllerManager(ctx.getOuterContext());
+ }});
+
registerService(Context.ROLE_SERVICE, RoleManager.class,
new CachedServiceFetcher<RoleManager>() {
@Override
@@ -1169,6 +1179,16 @@ final class SystemServiceRegistry {
throws ServiceNotFoundException {
return new RoleManager(ctx.getOuterContext());
}});
+
+ registerService(Context.ROLLBACK_SERVICE, RollbackManager.class,
+ new CachedServiceFetcher<RollbackManager>() {
+ @Override
+ public RollbackManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.ROLLBACK_SERVICE);
+ return new RollbackManager(ctx.getOuterContext(),
+ IRollbackManager.Stub.asInterface(b));
+ }});
//CHECKSTYLE:ON IndentationCheck
}
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index beb1c78388c9..121161e1a2f0 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -29,6 +29,7 @@ import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -174,7 +175,7 @@ public final class DeviceAdminInfo implements Parcelable {
/** @hide */
public static class PolicyInfo {
public final int ident;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final String tag;
public final int label;
public final int description;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 03e5933d300d..7da67d9e14e4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -55,6 +55,7 @@ import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -906,9 +907,8 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
/**
- * A String extra holding the URL-safe base64 encoded SHA-256 or SHA-1 hash (see notes below) of
- * the file at download location specified in
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+ * A String extra holding the URL-safe base64 encoded SHA-256 hash of the file at download
+ * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
*
* <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} must be
* present. The provided checksum must match the checksum of the file at the download
@@ -921,7 +921,8 @@ public class DevicePolicyManager {
* <p><strong>Note:</strong> for devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* and {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} only SHA-1 hash is supported.
* Starting from {@link android.os.Build.VERSION_CODES#M}, this parameter accepts SHA-256 in
- * addition to SHA-1. Support for SHA-1 is likely to be removed in future OS releases.
+ * addition to SHA-1. From {@link android.os.Build.VERSION_CODES#Q}, only SHA-256 hash is
+ * supported.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
@@ -2487,7 +2488,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2553,7 +2554,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2623,7 +2624,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2693,7 +2694,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2762,7 +2763,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2831,7 +2832,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2899,7 +2900,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -2968,7 +2969,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
@@ -3120,7 +3121,7 @@ public class DevicePolicyManager {
}
/** @hide per-user version */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index bdbce5282b94..ff7e181ba358 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -4,6 +4,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -14,18 +15,18 @@ import android.os.Parcelable;
* {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
*/
public class AssistContent implements Parcelable {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mIsAppProvidedIntent = false;
private boolean mIsAppProvidedWebUri = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Intent mIntent;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mStructuredData;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private ClipData mClipData;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Uri mUri;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Bundle mExtras;
public AssistContent() {
@@ -174,7 +175,7 @@ public class AssistContent implements Parcelable {
mIsAppProvidedWebUri = in.readInt() == 1;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
void writeToParcelInternal(Parcel dest, int flags) {
if (mIntent != null) {
dest.writeInt(1);
diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java
index bfc6df260e80..f804681cb3e9 100644
--- a/core/java/android/app/job/JobWorkItem.java
+++ b/core/java/android/app/job/JobWorkItem.java
@@ -21,6 +21,7 @@ import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
import android.annotation.BytesLong;
import android.annotation.UnsupportedAppUsage;
import android.content.Intent;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,15 +31,15 @@ import android.os.Parcelable;
* {@link JobParameters#dequeueWork() JobParameters.dequeueWork} for more details.
*/
final public class JobWorkItem implements Parcelable {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Intent mIntent;
final long mNetworkDownloadBytes;
final long mNetworkUploadBytes;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mDeliveryCount;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mWorkId;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Object mGrants;
/**
@@ -224,7 +225,7 @@ final public class JobWorkItem implements Parcelable {
}
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
JobWorkItem(Parcel in) {
if (in.readInt() != 0) {
mIntent = Intent.CREATOR.createFromParcel(in);
diff --git a/core/java/android/app/usage/ConfigurationStats.java b/core/java/android/app/usage/ConfigurationStats.java
index dff9b611010f..87a737db09b2 100644
--- a/core/java/android/app/usage/ConfigurationStats.java
+++ b/core/java/android/app/usage/ConfigurationStats.java
@@ -17,6 +17,7 @@ package android.app.usage;
import android.annotation.UnsupportedAppUsage;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,37 +30,37 @@ public final class ConfigurationStats implements Parcelable {
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public Configuration mConfiguration;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mBeginTimeStamp;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mEndTimeStamp;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mLastTimeActive;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mTotalTimeActive;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int mActivationCount;
/**
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index a06213d77a68..d7a53281bc56 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -19,6 +19,7 @@ import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.res.Configuration;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -268,13 +269,13 @@ public final class UsageEvents implements Parcelable {
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String mPackage;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String mClass;
@@ -286,20 +287,20 @@ public final class UsageEvents implements Parcelable {
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mTimeStamp;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int mEventType;
/**
* Only present for {@link #CONFIGURATION_CHANGE} event types.
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public Configuration mConfiguration;
/**
@@ -501,30 +502,30 @@ public final class UsageEvents implements Parcelable {
}
// Only used when creating the resulting events. Not used for reading/unparceling.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private List<Event> mEventsToWrite = null;
// Only used for reading/unparceling events.
@UnsupportedAppUsage
private Parcel mParcel = null;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mEventCount;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mIndex = 0;
/*
* In order to save space, since ComponentNames will be duplicated everywhere,
* we use a map and index into it.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String[] mStringPool;
/**
* Construct the iterator from a parcel.
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public UsageEvents(Parcel in) {
byte[] bytes = in.readBlob();
Parcel data = Parcel.obtain();
@@ -609,7 +610,7 @@ public final class UsageEvents implements Parcelable {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int findStringIndex(String str) {
final int index = Arrays.binarySearch(mStringPool, str);
if (index < 0) {
@@ -621,7 +622,7 @@ public final class UsageEvents implements Parcelable {
/**
* Writes a single event to the parcel. Modify this when updating {@link Event}.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void writeEventToParcel(Event event, Parcel p, int flags) {
final int packageIndex;
if (event.mPackage != null) {
@@ -666,7 +667,7 @@ public final class UsageEvents implements Parcelable {
/**
* Reads a single event from the parcel. Modify this when updating {@link Event}.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void readEventFromParcel(Parcel p, Event eventOut) {
final int packageIndex = p.readInt();
if (packageIndex >= 0) {
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 8fb7f4cb4d99..308180badbb8 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -29,6 +29,7 @@ import static android.app.usage.UsageEvents.Event.ROLLOVER_FOREGROUND_SERVICE;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -44,19 +45,19 @@ public final class UsageStats implements Parcelable {
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String mPackageName;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mBeginTimeStamp;
/**
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mEndTimeStamp;
/**
@@ -64,7 +65,7 @@ public final class UsageStats implements Parcelable {
* {@link android.app.usage.UsageEvents.Event#ACTIVITY_RESUMED} event.
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public long mLastTimeUsed;
/**
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3f348033a8aa..26beb45be13f 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -233,7 +233,7 @@ public final class UsageStatsManager {
@SystemApi
public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static final UsageEvents sEmptyResults = new UsageEvents();
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 466b9cee10a0..171c2f5b1a08 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -878,7 +878,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static String stateToString(int state) {
switch (state) {
case STATE_DISCONNECTED:
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 3a78cbdd4d0a..1edbacbae4f7 100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -18,6 +18,7 @@ package android.bluetooth;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,7 +66,7 @@ public final class BluetoothClass implements Parcelable {
private final int mClass;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public BluetoothClass(int classInt) {
mClass = classInt;
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index fdbfec00e627..bc3c9a9ebf4b 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.ParcelUuid;
import java.nio.ByteBuffer;
@@ -38,20 +39,20 @@ public final class BluetoothUuid {
* The following 128 bit values are calculated as:
* uuid * 2^96 + BASE_UUID
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final ParcelUuid AudioSink =
ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid AudioSource =
ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final ParcelUuid AdvAudioDist =
ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final ParcelUuid HSP =
ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid HSP_AG =
ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final ParcelUuid Handsfree =
ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid Handsfree_AG =
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5c9fced0f2cb..eb7be6f8a6b0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3123,6 +3123,7 @@ public abstract class Context {
APPWIDGET_SERVICE,
//@hide: VOICE_INTERACTION_MANAGER_SERVICE,
//@hide: BACKUP_SERVICE,
+ ROLLBACK_SERVICE,
DROPBOX_SERVICE,
//@hide: DEVICE_IDLE_CONTROLLER,
DEVICE_POLICY_SERVICE,
@@ -3992,6 +3993,14 @@ public abstract class Context {
public static final String PERMISSION_SERVICE = "permission";
/**
+ * Official published name of the (internal) permission controller service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve an
* {@link android.app.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
@@ -4003,6 +4012,17 @@ public abstract class Context {
public static final String BACKUP_SERVICE = "backup";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.content.rollback.RollbackManager} for communicating
+ * with the rollback manager
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ @SystemApi
+ public static final String ROLLBACK_SERVICE = "rollback";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.os.DropBoxManager} instance for recording
* diagnostic logs.
diff --git a/core/java/android/content/Entity.java b/core/java/android/content/Entity.java
index b9473e04c63c..ff4f15006280 100644
--- a/core/java/android/content/Entity.java
+++ b/core/java/android/content/Entity.java
@@ -18,6 +18,7 @@ package android.content;
import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
+import android.os.Build;
import java.util.ArrayList;
@@ -29,9 +30,9 @@ import java.util.ArrayList;
* corresponds to that RawContact. The uri refers to the Data table uri for each row.
*/
public final class Entity {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final private ContentValues mValues;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final private ArrayList<NamedContentValues> mSubValues;
public Entity(ContentValues values) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d5c6c63243f6..7b3497b8b483 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2248,6 +2248,32 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
/**
+ * Broadcast Action: Sent to the system rollback manager when a package
+ * needs to have rollback enabled.
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ * </p>
+ *
+ * @hide This broadcast is used internally by the system.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_ENABLE_ROLLBACK =
+ "android.intent.action.PACKAGE_ENABLE_ROLLBACK";
+ /**
+ * Broadcast Action: An existing version of an application package has been
+ * rolled back to a previous version.
+ * The data contains the name of the package.
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
+ "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
+ /**
* @hide
* Broadcast Action: Ask system services if there is any reason to
* restart the given package. The data contains the name of the
@@ -9142,7 +9168,7 @@ public class Intent implements Parcelable, Cloneable {
* @param extras The new set of extras in the Intent, or null to erase
* all extras.
*/
- public @NonNull Intent replaceExtras(@NonNull Bundle extras) {
+ public @NonNull Intent replaceExtras(@Nullable Bundle extras) {
mExtras = extras != null ? new Bundle(extras) : null;
return this;
}
@@ -10343,6 +10369,7 @@ public class Intent implements Parcelable, Cloneable {
case ACTION_MEDIA_SCANNER_SCAN_FILE:
case ACTION_PACKAGE_NEEDS_VERIFICATION:
case ACTION_PACKAGE_VERIFIED:
+ case ACTION_PACKAGE_ENABLE_ROLLBACK:
// Ignore legacy actions
break;
default:
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index ff77676505a7..6cd4841b9cf0 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -18,6 +18,7 @@ package android.content;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.text.TextUtils;
import android.os.Parcelable;
import android.os.Parcel;
@@ -30,9 +31,9 @@ public class SyncAdapterType implements Parcelable {
public final String authority;
public final String accountType;
public final boolean isKey;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final boolean userVisible;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final boolean supportsUploading;
@UnsupportedAppUsage
private final boolean isAlwaysSyncable;
@@ -85,7 +86,7 @@ public class SyncAdapterType implements Parcelable {
this.packageName = packageName;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private SyncAdapterType(String authority, String accountType) {
if (TextUtils.isEmpty(authority)) {
throw new IllegalArgumentException("the authority must not be empty: " + authority);
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index 7ebf922aead0..403cbcbf8b2f 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -18,6 +18,7 @@ package android.content;
import android.accounts.Account;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -95,7 +96,7 @@ public class SyncInfo implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
SyncInfo(Parcel parcel) {
authorityId = parcel.readInt();
account = parcel.readParcelable(Account.class.getClassLoader());
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 07b23d1decc0..dd550032df7c 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -19,6 +19,7 @@ package android.content.om;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -114,7 +115,7 @@ public final class OverlayInfo implements Parcelable {
/**
* Package name of the target package
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final String targetPackageName;
/**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 0c438afd7a83..2978058b2848 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
@@ -638,6 +639,21 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;
+ /**
+ * Indicate whether this application prefers code integrity, that is, run only code that is
+ * signed. This requires android:extractNativeLibs to be "false", as well as .dex and .so (if
+ * any) stored uncompressed inside the APK, which is signed. At run time, the implications
+ * include:
+ *
+ * <ul>
+ * <li>ART will JIT the dex code directly from the APK. There may be performance characteristic
+ * changes depend on the actual workload.
+ * </ul>
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_PREFER_CODE_INTEGRITY = 1 << 25;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -653,6 +669,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,
PRIVATE_FLAG_OEM,
PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
+ PRIVATE_FLAG_PREFER_CODE_INTEGRITY,
PRIVATE_FLAG_PRIVILEGED,
PRIVATE_FLAG_PRODUCT,
PRIVATE_FLAG_PRODUCT_SERVICES,
@@ -1449,9 +1466,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return sCollator.compare(sa.toString(), sb.toString());
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Collator sCollator = Collator.getInstance();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private PackageManager mPM;
}
@@ -1693,7 +1710,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void disableCompatibilityMode() {
flags |= (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS |
FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
@@ -1829,7 +1846,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return pm.getDefaultActivityIcon();
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean isPackageUnavailable(PackageManager pm) {
try {
return pm.getPackageInfo(packageName, 0) == null;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a4ea513a055f..64a4479be7ee 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -277,7 +277,7 @@ interface IPackageManager {
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
- boolean canSuspendPackageForUser(String packageName, int userId);
+ String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
boolean isPackageSuspendedForUser(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 099d15ad61c2..b8d7889c86ff 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.apex.ApexInfo;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -514,7 +515,7 @@ public class PackageInfo implements Parcelable {
}
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private PackageInfo(Parcel source) {
packageName = source.readString();
splitNames = source.createStringArray();
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index e0e67b9321aa..b878a955c223 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -116,7 +117,7 @@ public class PackageInfoLite implements Parcelable {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final Parcelable.Creator<PackageInfoLite> CREATOR
= new Parcelable.Creator<PackageInfoLite>() {
public PackageInfoLite createFromParcel(Parcel source) {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f06df3d4dfba..94b7c4538c51 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1425,6 +1425,15 @@ public class PackageInstaller {
this.grantedRuntimePermissions = permissions;
}
+ /**
+ * Request that rollbacks be enabled for the given upgrade.
+ * @hide
+ */
+ @SystemApi
+ public void setEnableRollback() {
+ installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
+ }
+
/** {@hide} */
@SystemApi
public void setAllowDowngrade(boolean allowDowngrade) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9d604bbd75aa..2aeb68da365b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -720,6 +720,9 @@ public abstract class PackageManager {
INSTALL_FORCE_SDK,
INSTALL_FULL_APP,
INSTALL_ALLOCATE_AGGRESSIVE,
+ INSTALL_VIRTUAL_PRELOAD,
+ INSTALL_APEX,
+ INSTALL_ENABLE_ROLLBACK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -857,6 +860,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_APEX = 0x00020000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that rollback
+ * should be enabled for this install.
+ *
+ * @hide
+ */
+ public static final int INSTALL_ENABLE_ROLLBACK = 0x00040000;
+
/** @hide */
@IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
DONT_KILL_APP
@@ -1357,6 +1368,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_BAD_DEX_METADATA = -117;
+ /**
+ * Installation parse return code: this is passed in the
+ * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if there is any signature problem.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_BAD_SIGNATURE = -118;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -1920,6 +1939,30 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports uicc-
+ * based NFC card emulation.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC =
+ "android.hardware.nfc.uicc";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports eSE-
+ * based NFC card emulation.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The Beam API is enabled on the device.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_NFC_BEAM = "android.sofware.nfc.beam";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports any
* one of the {@link #FEATURE_NFC}, {@link #FEATURE_NFC_HOST_CARD_EMULATION},
* or {@link #FEATURE_NFC_HOST_CARD_EMULATION_NFCF} features.
@@ -5958,27 +6001,28 @@ public abstract class PackageManager {
}
/**
- * Returns whether or not a given package can be suspended via a call to {@link
+ * Returns any packages in a given set of packages that cannot be suspended via a call to {@link
* #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
* SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
* packages to keep the device in a functioning state, e.g. the default dialer.
* Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this api.
*
* <p>
- * Note that this set of critical packages can change with time, so <em>a value of {@code true}
- * returned by this api does not guarantee that a following call to {@link
- * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
- * SuspendDialogInfo) setPackagesSuspended} for the same package will succeed</em>, especially
- * if considerable time elapsed between the two calls.
+ * Note that this set of critical packages can change with time, so even though a package name
+ * was not returned by this call, it does not guarantee that a subsequent call to
+ * {@link #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+ * SuspendDialogInfo) setPackagesSuspended} for that package will succeed, especially if
+ * significant time elapsed between the two calls.
*
- * @param packageName The package to check.
- * @return {@code true} if the given package can be suspended, {@code false} otherwise.
+ * @param packageNames The packages to check.
+ * @return A list of packages that can not be currently suspended by the system.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.SUSPEND_APPS)
- public boolean canSuspendPackage(@NonNull String packageName) {
- throw new UnsupportedOperationException("canSuspendPackage not implemented");
+ @NonNull
+ public String[] getUnsuspendablePackages(@NonNull String[] packageNames) {
+ throw new UnsupportedOperationException("canSuspendPackages not implemented");
}
/**
@@ -6231,6 +6275,7 @@ public abstract class PackageManager {
case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA";
case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";
+ case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE";
default: return Integer.toString(status);
}
}
@@ -6276,6 +6321,7 @@ public abstract class PackageManager {
case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID;
case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID;
case INSTALL_FAILED_BAD_DEX_METADATA: return PackageInstaller.STATUS_FAILURE_INVALID;
+ case INSTALL_FAILED_BAD_SIGNATURE: return PackageInstaller.STATUS_FAILURE_INVALID;
case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;
case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 5db9f506e6e4..83979e925be1 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -759,4 +759,48 @@ public abstract class PackageManagerInternal {
/** Returns whether the given package is enabled for the given user */
public abstract @PackageManager.EnabledState int getApplicationEnabledState(
String packageName, int userId);
+
+ /**
+ * Extra field name for the token of a request to enable rollback for a
+ * package.
+ */
+ public static final String EXTRA_ENABLE_ROLLBACK_TOKEN =
+ "android.content.pm.extra.ENABLE_ROLLBACK_TOKEN";
+
+ /**
+ * Extra field name for the installFlags of a request to enable rollback
+ * for a package.
+ */
+ public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS =
+ "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
+
+ /**
+ * Used as the {@code enableRollbackCode} argument for
+ * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that
+ * enabling rollback succeeded.
+ */
+ public static final int ENABLE_ROLLBACK_SUCCEEDED = 1;
+
+ /**
+ * Used as the {@code enableRollbackCode} argument for
+ * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that
+ * enabling rollback failed.
+ */
+ public static final int ENABLE_ROLLBACK_FAILED = -1;
+
+ /**
+ * Allows the rollback manager listening to the
+ * {@link Intent#ACTION_PACKAGE_ENABLE_ROLLBACK enable rollback broadcast}
+ * to respond to the package manager. The response must include the
+ * {@code enableRollbackCode} which is one of
+ * {@link PackageManager#ENABLE_ROLLBACK_SUCCEEDED} or
+ * {@link PackageManager#ENABLE_ROLLBACK_FAILED}.
+ *
+ * @param token pending package identifier as passed via the
+ * {@link PackageManager#EXTRA_ENABLE_ROLLBACK_TOKEN} Intent extra.
+ * @param enableRollbackCode the status code result of enabling rollback
+ * @throws SecurityException if the caller does not have the
+ * PACKAGE_ROLLBACK_AGENT permission.
+ */
+ public abstract void setEnableRollbackCode(int token, int enableRollbackCode);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e38b294b4485..2b266b730485 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -475,6 +475,7 @@ public class PackageParser {
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
public final boolean isSplitRequired;
+ public final boolean preferCodeIntegrity;
public ApkLite(String codePath, String packageName, String splitName,
boolean isFeatureSplit,
@@ -483,7 +484,7 @@ public class PackageParser {
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
SigningDetails signingDetails, boolean coreApp,
boolean debuggable, boolean multiArch, boolean use32bitAbi,
- boolean extractNativeLibs, boolean isolatedSplits) {
+ boolean preferCodeIntegrity, boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -500,6 +501,7 @@ public class PackageParser {
this.debuggable = debuggable;
this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi;
+ this.preferCodeIntegrity = preferCodeIntegrity;
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
this.isSplitRequired = isSplitRequired;
@@ -1722,6 +1724,7 @@ public class PackageParser {
boolean isolatedSplits = false;
boolean isFeatureSplit = false;
boolean isSplitRequired = false;
+ boolean preferCodeIntegrity = false;
String configForSplit = null;
String usesSplitName = null;
@@ -1784,6 +1787,9 @@ public class PackageParser {
if ("extractNativeLibs".equals(attr)) {
extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
+ if ("preferCodeIntegrity".equals(attr)) {
+ preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false);
+ }
}
} else if (TAG_USES_SPLIT.equals(parser.getName())) {
if (usesSplitName != null) {
@@ -1800,10 +1806,16 @@ public class PackageParser {
}
}
+ if (preferCodeIntegrity && extractNativeLibs) {
+ throw new PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Can't request both preferCodeIntegrity and extractNativeLibs");
+ }
+
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
- multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
+ multiArch, use32bitAbi, preferCodeIntegrity, extractNativeLibs, isolatedSplits);
}
/**
@@ -3655,6 +3667,12 @@ public class PackageParser {
}
if (sa.getBoolean(
+ R.styleable.AndroidManifestApplication_preferCodeIntegrity,
+ false)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY;
+ }
+
+ if (sa.getBoolean(
R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
false)) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index f70ec390e90e..d3e86a35170e 100644
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -18,6 +18,7 @@ package android.content.pm;
import android.annotation.UnsupportedAppUsage;
import android.app.usage.StorageStatsManager;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -38,7 +39,7 @@ public class PackageStats implements Parcelable {
public String packageName;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int userHandle;
/** Size of the code (e.g., APK) */
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 1ca7b132fdab..7d101b8f78e5 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -612,7 +612,7 @@ public class CompatibilityInfo implements Parcelable {
dest.writeFloat(applicationInvertedScale);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final Parcelable.Creator<CompatibilityInfo> CREATOR
= new Parcelable.Creator<CompatibilityInfo>() {
@Override
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
new file mode 100644
index 000000000000..7f557cd8bbe8
--- /dev/null
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.rollback;
+
+import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
+import android.content.rollback.RollbackInfo;
+import android.content.IntentSender;
+
+/** {@hide} */
+interface IRollbackManager {
+
+ RollbackInfo getAvailableRollback(String packageName);
+
+ StringParceledListSlice getPackagesWithAvailableRollbacks();
+
+ ParceledListSlice getRecentlyExecutedRollbacks();
+
+ void executeRollback(in RollbackInfo rollback, String callerPackageName,
+ in IntentSender statusReceiver);
+
+ // Exposed for test purposes only.
+ void reloadPersistedData();
+
+ // Exposed for test purposes only.
+ void expireRollbackForPackage(String packageName);
+}
diff --git a/core/java/android/hardware/display/BrightnessCorrection.aidl b/core/java/android/content/rollback/PackageRollbackInfo.aidl
index 3abe29cc0076..9cb52c982754 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.aidl
+++ b/core/java/android/content/rollback/PackageRollbackInfo.aidl
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.content.rollback;
-package android.hardware.display;
-
-parcelable BrightnessCorrection;
+parcelable PackageRollbackInfo;
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
new file mode 100644
index 000000000000..204002426d17
--- /dev/null
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.rollback;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Information about a rollback available for a particular package.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PackageRollbackInfo implements Parcelable {
+ /**
+ * The name of a package being rolled back.
+ */
+ public final String packageName;
+
+ /**
+ * The version the package was rolled back from.
+ */
+ public final PackageVersion higherVersion;
+
+ /**
+ * The version the package was rolled back to.
+ */
+ public final PackageVersion lowerVersion;
+
+ /**
+ * Represents a version of a package.
+ */
+ public static class PackageVersion {
+ public final long versionCode;
+
+ // TODO(b/120200473): Include apk sha or some other way to distinguish
+ // between two different apks with the same version code.
+ public PackageVersion(long versionCode) {
+ this.versionCode = versionCode;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof PackageVersion) {
+ PackageVersion otherVersion = (PackageVersion) other;
+ return versionCode == otherVersion.versionCode;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(versionCode);
+ }
+ }
+
+ public PackageRollbackInfo(String packageName,
+ PackageVersion higherVersion, PackageVersion lowerVersion) {
+ this.packageName = packageName;
+ this.higherVersion = higherVersion;
+ this.lowerVersion = lowerVersion;
+ }
+
+ private PackageRollbackInfo(Parcel in) {
+ this.packageName = in.readString();
+ this.higherVersion = new PackageVersion(in.readLong());
+ this.lowerVersion = new PackageVersion(in.readLong());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(packageName);
+ out.writeLong(higherVersion.versionCode);
+ out.writeLong(lowerVersion.versionCode);
+ }
+
+ public static final Parcelable.Creator<PackageRollbackInfo> CREATOR =
+ new Parcelable.Creator<PackageRollbackInfo>() {
+ public PackageRollbackInfo createFromParcel(Parcel in) {
+ return new PackageRollbackInfo(in);
+ }
+
+ public PackageRollbackInfo[] newArray(int size) {
+ return new PackageRollbackInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/rollback/RollbackInfo.aidl b/core/java/android/content/rollback/RollbackInfo.aidl
new file mode 100644
index 000000000000..a9dc5cd59cbb
--- /dev/null
+++ b/core/java/android/content/rollback/RollbackInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.rollback;
+
+parcelable RollbackInfo;
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
new file mode 100644
index 000000000000..66df4fea3f23
--- /dev/null
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.rollback;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about a set of packages that can be, or already have been
+ * rolled back together.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RollbackInfo implements Parcelable {
+
+ /**
+ * The package that needs to be rolled back.
+ */
+ public final PackageRollbackInfo targetPackage;
+
+ // TODO: Add a list of additional packages rolled back due to atomic
+ // install dependencies when rollback of atomic installs is supported.
+ // TODO: Add a flag to indicate if reboot is required, when rollback of
+ // staged installs is supported.
+
+ /** @hide */
+ public RollbackInfo(PackageRollbackInfo targetPackage) {
+ this.targetPackage = targetPackage;
+ }
+
+ private RollbackInfo(Parcel in) {
+ this.targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ targetPackage.writeToParcel(out, flags);
+ }
+
+ public static final Parcelable.Creator<RollbackInfo> CREATOR =
+ new Parcelable.Creator<RollbackInfo>() {
+ public RollbackInfo createFromParcel(Parcel in) {
+ return new RollbackInfo(in);
+ }
+
+ public RollbackInfo[] newArray(int size) {
+ return new RollbackInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
new file mode 100644
index 000000000000..c1c0bc1d3e07
--- /dev/null
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.rollback;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.IntentSender;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Offers the ability to rollback packages after upgrade.
+ * <p>
+ * For packages installed with rollbacks enabled, the RollbackManager can be
+ * used to initiate rollback of those packages for a limited time period after
+ * upgrade.
+ *
+ * @see PackageInstaller.SessionParams#setEnableRollback()
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.ROLLBACK_SERVICE)
+public final class RollbackManager {
+ private final String mCallerPackageName;
+ private final IRollbackManager mBinder;
+
+ /** {@hide} */
+ public RollbackManager(Context context, IRollbackManager binder) {
+ mCallerPackageName = context.getPackageName();
+ mBinder = binder;
+ }
+
+ /**
+ * Returns the rollback currently available to be executed for the given
+ * package.
+ * <p>
+ * The returned RollbackInfo describes what packages would be rolled back,
+ * including package version codes before and after rollback. The rollback
+ * can be initiated using {@link #executeRollback(RollbackInfo,IntentSender)}.
+ * <p>
+ * TODO: What if there is no package installed on device for packageName?
+ *
+ * @param packageName name of the package to get the availble RollbackInfo for.
+ * @return the rollback available for the package, or null if no rollback
+ * is available for the package.
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
+ try {
+ return mBinder.getAvailableRollback(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the names of packages that are available for rollback.
+ * Call {@link #getAvailableRollback(String)} to get more information
+ * about the rollback available for a particular package.
+ *
+ * @return the names of packages that are available for rollback.
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public @NonNull List<String> getPackagesWithAvailableRollbacks() {
+ try {
+ return mBinder.getPackagesWithAvailableRollbacks().getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Gets the list of all recently executed rollbacks.
+ * This is for the purposes of preventing re-install of a bad version of a
+ * package.
+ * <p>
+ * Returns an empty list if there are no recently executed rollbacks.
+ * <p>
+ * To avoid having to keep around complete rollback history forever on a
+ * device, the returned list of rollbacks is only guaranteed to include
+ * rollbacks that are still relevant. A rollback is no longer considered
+ * relevant if the package is subsequently uninstalled or upgraded
+ * (without the possibility of rollback) to a higher version code than was
+ * rolled back from.
+ *
+ * @return the recently executed rollbacks
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
+ try {
+ return mBinder.getRecentlyExecutedRollbacks().getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Execute the given rollback, rolling back all versions of the packages
+ * to the last good versions previously installed on the device as
+ * specified in the given rollback object. The rollback will fail if any
+ * of the installed packages or available rollbacks are inconsistent with
+ * the versions specified in the given rollback object, which can happen
+ * if a package has been updated or a rollback expired since the rollback
+ * object was retrieved from {@link #getAvailableRollback(String)}.
+ * <p>
+ * TODO: Specify the returns status codes.
+ * TODO: What happens in case reboot is required for the rollback to take
+ * effect for staged installs?
+ *
+ * @param rollback to execute
+ * @param statusReceiver where to deliver the results
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public void executeRollback(@NonNull RollbackInfo rollback,
+ @NonNull IntentSender statusReceiver) {
+ try {
+ mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Reload all persisted rollback data from device storage.
+ * This API is meant to test that rollback state is properly preserved
+ * across device reboot, by simulating what happens on reboot without
+ * actually rebooting the device.
+ *
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public void reloadPersistedData() {
+ try {
+ mBinder.reloadPersistedData();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Expire the rollback data for a given package.
+ * This API is meant to facilitate testing of rollback logic for
+ * expiring rollback data.
+ *
+ * @param packageName the name of the package to expire data for.
+ * @throws SecurityException if the caller does not have the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ public void expireRollbackForPackage(@NonNull String packageName) {
+ try {
+ mBinder.expireRollbackForPackage(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index f78b484e0491..992da312201d 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -30,6 +30,7 @@ import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteProgram;
import android.database.sqlite.SQLiteStatement;
+import android.os.Build;
import android.os.OperationCanceledException;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
@@ -322,7 +323,7 @@ public class DatabaseUtils {
* @return object value type
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int getTypeOfObject(Object obj) {
if (obj == null) {
return Cursor.FIELD_TYPE_NULL;
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index 5033296df9fb..a52e96e249f8 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -17,6 +17,7 @@
package android.database;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import java.util.ArrayList;
/**
@@ -27,9 +28,9 @@ import java.util.ArrayList;
public class MatrixCursor extends AbstractCursor {
private final String[] columnNames;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Object[] data;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int rowCount = 0;
private final int columnCount;
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 4fce2d7fe0df..5722e7b25fbf 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -53,11 +53,11 @@ public class SQLiteQueryBuilder {
private Map<String, String> mProjectionMap = null;
private List<Pattern> mProjectionGreylist = null;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mTables = "";
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private StringBuilder mWhereClause = null; // lazily created
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mDistinct;
private SQLiteDatabase.CursorFactory mFactory;
private boolean mStrict;
@@ -800,7 +800,7 @@ public class SQLiteQueryBuilder {
return query.toString();
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String[] computeProjection(String[] projectionIn) {
if (projectionIn != null && projectionIn.length > 0) {
if (mProjectionMap != null) {
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index be054297c769..7e52ca331f9f 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -19,54 +19,26 @@ package android.hardware.display;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.content.pm.ApplicationInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import java.util.Objects;
/** @hide */
@SystemApi
@TestApi
public final class BrightnessConfiguration implements Parcelable {
- private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve";
- private static final String TAG_BRIGHTNESS_POINT = "brightness-point";
- private static final String TAG_BRIGHTNESS_CORRECTIONS = "brightness-corrections";
- private static final String TAG_BRIGHTNESS_CORRECTION = "brightness-correction";
- private static final String ATTR_LUX = "lux";
- private static final String ATTR_NITS = "nits";
- private static final String ATTR_DESCRIPTION = "description";
- private static final String ATTR_PACKAGE_NAME = "package-name";
- private static final String ATTR_CATEGORY = "category";
-
private final float[] mLux;
private final float[] mNits;
- private final Map<String, BrightnessCorrection> mCorrectionsByPackageName;
- private final Map<Integer, BrightnessCorrection> mCorrectionsByCategory;
private final String mDescription;
- private BrightnessConfiguration(float[] lux, float[] nits,
- Map<String, BrightnessCorrection> correctionsByPackageName,
- Map<Integer, BrightnessCorrection> correctionsByCategory, String description) {
+ private BrightnessConfiguration(float[] lux, float[] nits, String description) {
mLux = lux;
mNits = nits;
- mCorrectionsByPackageName = correctionsByPackageName;
- mCorrectionsByCategory = correctionsByCategory;
mDescription = description;
}
@@ -84,38 +56,6 @@ public final class BrightnessConfiguration implements Parcelable {
}
/**
- * Returns a brightness correction by app, or null.
- *
- * @param packageName
- * The app's package name.
- *
- * @return The matching brightness correction, or null.
- *
- * @hide
- */
- @SystemApi
- @Nullable
- public BrightnessCorrection getCorrectionByPackageName(String packageName) {
- return mCorrectionsByPackageName.get(packageName);
- }
-
- /**
- * Returns a brightness correction by app category, or null.
- *
- * @param category
- * The app category.
- *
- * @return The matching brightness correction, or null.
- *
- * @hide
- */
- @SystemApi
- @Nullable
- public BrightnessCorrection getCorrectionByCategory(int category) {
- return mCorrectionsByCategory.get(category);
- }
-
- /**
* Returns description string.
* @hide
*/
@@ -127,20 +67,6 @@ public final class BrightnessConfiguration implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeFloatArray(mLux);
dest.writeFloatArray(mNits);
- dest.writeInt(mCorrectionsByPackageName.size());
- for (Entry<String, BrightnessCorrection> entry : mCorrectionsByPackageName.entrySet()) {
- final String packageName = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- dest.writeString(packageName);
- correction.writeToParcel(dest, flags);
- }
- dest.writeInt(mCorrectionsByCategory.size());
- for (Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) {
- final int category = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- dest.writeInt(category);
- correction.writeToParcel(dest, flags);
- }
dest.writeString(mDescription);
}
@@ -159,14 +85,7 @@ public final class BrightnessConfiguration implements Parcelable {
}
sb.append("(").append(mLux[i]).append(", ").append(mNits[i]).append(")");
}
- sb.append("], {");
- for (Entry<String, BrightnessCorrection> entry : mCorrectionsByPackageName.entrySet()) {
- sb.append("'" + entry.getKey() + "': " + entry.getValue() + ", ");
- }
- for (Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) {
- sb.append(entry.getKey() + ": " + entry.getValue() + ", ");
- }
- sb.append("}, '");
+ sb.append("], '");
if (mDescription != null) {
sb.append(mDescription);
}
@@ -179,8 +98,6 @@ public final class BrightnessConfiguration implements Parcelable {
int result = 1;
result = result * 31 + Arrays.hashCode(mLux);
result = result * 31 + Arrays.hashCode(mNits);
- result = result * 31 + mCorrectionsByPackageName.hashCode();
- result = result * 31 + mCorrectionsByCategory.hashCode();
if (mDescription != null) {
result = result * 31 + mDescription.hashCode();
}
@@ -197,8 +114,6 @@ public final class BrightnessConfiguration implements Parcelable {
}
final BrightnessConfiguration other = (BrightnessConfiguration) o;
return Arrays.equals(mLux, other.mLux) && Arrays.equals(mNits, other.mNits)
- && mCorrectionsByPackageName.equals(other.mCorrectionsByPackageName)
- && mCorrectionsByCategory.equals(other.mCorrectionsByCategory)
&& Objects.equals(mDescription, other.mDescription);
}
@@ -208,25 +123,7 @@ public final class BrightnessConfiguration implements Parcelable {
float[] lux = in.createFloatArray();
float[] nits = in.createFloatArray();
Builder builder = new Builder(lux, nits);
-
- int n = in.readInt();
- for (int i = 0; i < n; i++) {
- final String packageName = in.readString();
- final BrightnessCorrection correction =
- BrightnessCorrection.CREATOR.createFromParcel(in);
- builder.addCorrectionByPackageName(packageName, correction);
- }
-
- n = in.readInt();
- for (int i = 0; i < n; i++) {
- final int category = in.readInt();
- final BrightnessCorrection correction =
- BrightnessCorrection.CREATOR.createFromParcel(in);
- builder.addCorrectionByCategory(category, correction);
- }
-
- final String description = in.readString();
- builder.setDescription(description);
+ builder.setDescription(in.readString());
return builder.build();
}
@@ -236,146 +133,11 @@ public final class BrightnessConfiguration implements Parcelable {
};
/**
- * Writes the configuration to an XML serializer.
- *
- * @param serializer
- * The XML serializer.
- *
- * @hide
- */
- public void saveToXml(XmlSerializer serializer) throws IOException {
- serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
- if (mDescription != null) {
- serializer.attribute(null, ATTR_DESCRIPTION, mDescription);
- }
- for (int i = 0; i < mLux.length; i++) {
- serializer.startTag(null, TAG_BRIGHTNESS_POINT);
- serializer.attribute(null, ATTR_LUX, Float.toString(mLux[i]));
- serializer.attribute(null, ATTR_NITS, Float.toString(mNits[i]));
- serializer.endTag(null, TAG_BRIGHTNESS_POINT);
- }
- serializer.endTag(null, TAG_BRIGHTNESS_CURVE);
- serializer.startTag(null, TAG_BRIGHTNESS_CORRECTIONS);
- for (Map.Entry<String, BrightnessCorrection> entry :
- mCorrectionsByPackageName.entrySet()) {
- final String packageName = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION);
- serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
- correction.saveToXml(serializer);
- serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION);
- }
- for (Map.Entry<Integer, BrightnessCorrection> entry : mCorrectionsByCategory.entrySet()) {
- final int category = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION);
- serializer.attribute(null, ATTR_CATEGORY, Integer.toString(category));
- correction.saveToXml(serializer);
- serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION);
- }
- serializer.endTag(null, TAG_BRIGHTNESS_CORRECTIONS);
- }
-
- /**
- * Read a configuration from an XML parser.
- *
- * @param parser
- * The XML parser.
- *
- * @throws IOException
- * The parser failed to read the XML file.
- * @throws XmlPullParserException
- * The parser failed to parse the XML file.
- *
- * @hide
- */
- public static BrightnessConfiguration loadFromXml(XmlPullParser parser)
- throws IOException, XmlPullParserException {
- String description = null;
- List<Float> luxList = new ArrayList<>();
- List<Float> nitsList = new ArrayList<>();
- Map<String, BrightnessCorrection> correctionsByPackageName = new HashMap<>();
- Map<Integer, BrightnessCorrection> correctionsByCategory = new HashMap<>();
- final int configDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, configDepth)) {
- if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) {
- description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
- final int curveDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, curveDepth)) {
- if (!TAG_BRIGHTNESS_POINT.equals(parser.getName())) {
- continue;
- }
- final float lux = loadFloatFromXml(parser, ATTR_LUX);
- final float nits = loadFloatFromXml(parser, ATTR_NITS);
- luxList.add(lux);
- nitsList.add(nits);
- }
- }
- if (TAG_BRIGHTNESS_CORRECTIONS.equals(parser.getName())) {
- final int correctionsDepth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, correctionsDepth)) {
- if (!TAG_BRIGHTNESS_CORRECTION.equals(parser.getName())) {
- continue;
- }
- final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- final String categoryText = parser.getAttributeValue(null, ATTR_CATEGORY);
- BrightnessCorrection correction = BrightnessCorrection.loadFromXml(parser);
- if (packageName != null) {
- correctionsByPackageName.put(packageName, correction);
- } else if (categoryText != null) {
- try {
- final int category = Integer.parseInt(categoryText);
- correctionsByCategory.put(category, correction);
- } catch (NullPointerException | NumberFormatException e) {
- continue;
- }
- }
- }
- }
- }
- final int n = luxList.size();
- float[] lux = new float[n];
- float[] nits = new float[n];
- for (int i = 0; i < n; i++) {
- lux[i] = luxList.get(i);
- nits[i] = nitsList.get(i);
- }
- final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(lux,
- nits);
- builder.setDescription(description);
- for (Map.Entry<String, BrightnessCorrection> entry : correctionsByPackageName.entrySet()) {
- final String packageName = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- builder.addCorrectionByPackageName(packageName, correction);
- }
- for (Map.Entry<Integer, BrightnessCorrection> entry : correctionsByCategory.entrySet()) {
- final int category = entry.getKey();
- final BrightnessCorrection correction = entry.getValue();
- builder.addCorrectionByCategory(category, correction);
- }
- return builder.build();
- }
-
- private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
- final String string = parser.getAttributeValue(null, attribute);
- try {
- return Float.parseFloat(string);
- } catch (NullPointerException | NumberFormatException e) {
- return Float.NaN;
- }
- }
-
- /**
* A builder class for {@link BrightnessConfiguration}s.
*/
public static class Builder {
- private static final int MAX_CORRECTIONS_BY_PACKAGE_NAME = 20;
- private static final int MAX_CORRECTIONS_BY_CATEGORY = 20;
-
private float[] mCurveLux;
private float[] mCurveNits;
- private Map<String, BrightnessCorrection> mCorrectionsByPackageName;
- private Map<Integer, BrightnessCorrection> mCorrectionsByCategory;
private String mDescription;
/**
@@ -407,88 +169,6 @@ public final class BrightnessConfiguration implements Parcelable {
checkMonotonic(nits, false /*strictly increasing*/, "nits");
mCurveLux = lux;
mCurveNits = nits;
- mCorrectionsByPackageName = new HashMap<>();
- mCorrectionsByCategory = new HashMap<>();
- }
-
- /**
- * Returns the maximum number of corrections by package name allowed.
- *
- * @return The maximum number of corrections by package name allowed.
- *
- * @hide
- */
- @SystemApi
- public int getMaxCorrectionsByPackageName() {
- return MAX_CORRECTIONS_BY_PACKAGE_NAME;
- }
-
- /**
- * Returns the maximum number of corrections by category allowed.
- *
- * @return The maximum number of corrections by category allowed.
- *
- * @hide
- */
- @SystemApi
- public int getMaxCorrectionsByCategory() {
- return MAX_CORRECTIONS_BY_CATEGORY;
- }
-
- /**
- * Add a brightness correction by app package name.
- * This correction is applied whenever an app with this package name has the top activity
- * of the focused stack.
- *
- * @param packageName
- * The app's package name.
- * @param correction
- * The brightness correction.
- *
- * @return The builder.
- *
- * @throws IllegalArgumentExceptions
- * Maximum number of corrections by package name exceeded (see
- * {@link #getMaxCorrectionsByPackageName}).
- *
- * @hide
- */
- @SystemApi
- public Builder addCorrectionByPackageName(String packageName,
- BrightnessCorrection correction) {
- if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) {
- throw new IllegalArgumentException("Too many corrections by package name");
- }
- mCorrectionsByPackageName.put(packageName, correction);
- return this;
- }
-
- /**
- * Add a brightness correction by app category.
- * This correction is applied whenever an app with this category has the top activity of
- * the focused stack, and only if a correction by package name has not been applied.
- *
- * @param category
- * The {@link android.content.pm.ApplicationInfo#category app category}.
- * @param correction
- * The brightness correction.
- *
- * @return The builder.
- *
- * @throws IllegalArgumentException
- * Maximum number of corrections by category exceeded (see
- * {@link #getMaxCorrectionsByCategory}).
- *
- * @hide
- */
- @SystemApi
- public Builder addCorrectionByCategory(@ApplicationInfo.Category int category,
- BrightnessCorrection correction) {
- if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) {
- throw new IllegalArgumentException("Too many corrections by category");
- }
- mCorrectionsByCategory.put(category, correction);
- return this;
}
/**
@@ -511,8 +191,7 @@ public final class BrightnessConfiguration implements Parcelable {
if (mCurveLux == null || mCurveNits == null) {
throw new IllegalStateException("A curve must be set!");
}
- return new BrightnessConfiguration(mCurveLux, mCurveNits, mCorrectionsByPackageName,
- mCorrectionsByCategory, mDescription);
+ return new BrightnessConfiguration(mCurveLux, mCurveNits, mDescription);
}
private static void checkMonotonic(float[] vals, boolean strictlyIncreasing, String name) {
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
deleted file mode 100644
index c4e0e3b723cd..000000000000
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ /dev/null
@@ -1,245 +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.
- */
-
-package android.hardware.display;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.MathUtils;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-
-/**
- * BrightnessCorrection encapsulates a correction to the brightness, without comitting to the
- * actual correction scheme.
- * It is used by the BrightnessConfiguration, which maps context (e.g. the foreground app's package
- * name and category) to corrections that need to be applied to the brightness within that context.
- * Corrections are currently done by the app that has the top activity of the focused stack, either
- * by its package name, or (if its package name is not mapped to any correction) by its category.
- *
- * @hide
- */
-@SystemApi
-public final class BrightnessCorrection implements Parcelable {
-
- private static final int SCALE_AND_TRANSLATE_LOG = 1;
-
- private static final String TAG_SCALE_AND_TRANSLATE_LOG = "scale-and-translate-log";
-
- private BrightnessCorrectionImplementation mImplementation;
-
- // Parcelable classes must be final, and protected methods are not allowed in APIs, so we can't
- // make this class abstract and use composition instead of inheritence.
- private BrightnessCorrection(BrightnessCorrectionImplementation implementation) {
- mImplementation = implementation;
- }
-
- /**
- * Creates a BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
- *
- * @param scale
- * How much to scale the log brightness.
- * @param translate
- * How much to translate the log brightness.
- *
- * @return A BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
- *
- * @throws IllegalArgumentException
- * - scale or translate are NaN.
- */
- @NonNull
- public static BrightnessCorrection createScaleAndTranslateLog(float scale, float translate) {
- BrightnessCorrectionImplementation implementation =
- new ScaleAndTranslateLog(scale, translate);
- return new BrightnessCorrection(implementation);
- }
-
- /**
- * Applies the brightness correction to a given brightness.
- *
- * @param brightness
- * The brightness.
- *
- * @return The corrected brightness.
- */
- public float apply(float brightness) {
- return mImplementation.apply(brightness);
- }
-
- /**
- * Returns a string representation.
- *
- * @return A string representation.
- */
- public String toString() {
- return mImplementation.toString();
- }
-
- public static final Creator<BrightnessCorrection> CREATOR =
- new Creator<BrightnessCorrection>() {
- public BrightnessCorrection createFromParcel(Parcel in) {
- final int type = in.readInt();
- switch (type) {
- case SCALE_AND_TRANSLATE_LOG:
- return ScaleAndTranslateLog.readFromParcel(in);
- }
- return null;
- }
-
- public BrightnessCorrection[] newArray(int size) {
- return new BrightnessCorrection[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mImplementation.writeToParcel(dest);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Writes the correction to an XML serializer.
- *
- * @param serializer
- * The XML serializer.
- *
- * @hide
- */
- public void saveToXml(XmlSerializer serializer) throws IOException {
- mImplementation.saveToXml(serializer);
- }
-
- /**
- * Read a correction from an XML parser.
- *
- * @param parser
- * The XML parser.
- *
- * @throws IOException
- * The parser failed to read the XML file.
- * @throws XmlPullParserException
- * The parser failed to parse the XML file.
- *
- * @hide
- */
- public static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
- XmlPullParserException {
- final int depth = parser.getDepth();
- while (XmlUtils.nextElementWithin(parser, depth)) {
- if (TAG_SCALE_AND_TRANSLATE_LOG.equals(parser.getName())) {
- return ScaleAndTranslateLog.loadFromXml(parser);
- }
- }
- return null;
- }
-
- private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
- final String string = parser.getAttributeValue(null, attribute);
- try {
- return Float.parseFloat(string);
- } catch (NullPointerException | NumberFormatException e) {
- return Float.NaN;
- }
- }
-
- private interface BrightnessCorrectionImplementation {
- float apply(float brightness);
- String toString();
- void writeToParcel(Parcel dest);
- void saveToXml(XmlSerializer serializer) throws IOException;
- // Package-private static methods:
- // static BrightnessCorrection readFromParcel(Parcel in);
- // static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
- // XmlPullParserException;
- }
-
- /**
- * A BrightnessCorrection that given {@code brightness}, corrects it to be
- * {@code exp(scale * log(brightness) + translate)}.
- */
- private static class ScaleAndTranslateLog implements BrightnessCorrectionImplementation {
- private static final float MIN_SCALE = 0.5f;
- private static final float MAX_SCALE = 2.0f;
- private static final float MIN_TRANSLATE = -0.6f;
- private static final float MAX_TRANSLATE = 0.7f;
-
- private static final String ATTR_SCALE = "scale";
- private static final String ATTR_TRANSLATE = "translate";
-
- private final float mScale;
- private final float mTranslate;
-
- ScaleAndTranslateLog(float scale, float translate) {
- if (Float.isNaN(scale) || Float.isNaN(translate)) {
- throw new IllegalArgumentException("scale and translate must be numbers");
- }
- mScale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
- mTranslate = MathUtils.constrain(translate, MIN_TRANSLATE, MAX_TRANSLATE);
- }
-
- @Override
- public float apply(float brightness) {
- return MathUtils.exp(mScale * MathUtils.log(brightness) + mTranslate);
- }
-
- @Override
- public String toString() {
- return "ScaleAndTranslateLog(" + mScale + ", " + mTranslate + ")";
- }
-
- @Override
- public void writeToParcel(Parcel dest) {
- dest.writeInt(SCALE_AND_TRANSLATE_LOG);
- dest.writeFloat(mScale);
- dest.writeFloat(mTranslate);
- }
-
- @Override
- public void saveToXml(XmlSerializer serializer) throws IOException {
- serializer.startTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
- serializer.attribute(null, ATTR_SCALE, Float.toString(mScale));
- serializer.attribute(null, ATTR_TRANSLATE, Float.toString(mTranslate));
- serializer.endTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
- }
-
- static BrightnessCorrection readFromParcel(Parcel in) {
- float scale = in.readFloat();
- float translate = in.readFloat();
- return BrightnessCorrection.createScaleAndTranslateLog(scale, translate);
- }
-
- static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
- XmlPullParserException {
- final float scale = loadFloatFromXml(parser, ATTR_SCALE);
- final float translate = loadFloatFromXml(parser, ATTR_TRANSLATE);
- return BrightnessCorrection.createScaleAndTranslateLog(scale, translate);
- }
- }
-}
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index a4c1332b45d1..dd782ec3a42f 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -60,6 +60,13 @@ public final class ColorDisplayManager {
return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
}
+ /**
+ * Returns {@code true} if display white balance is supported by the device.
+ */
+ public static boolean isDisplayWhiteBalanceAvailable(Context context) {
+ return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
+ }
+
private static class ColorDisplayManagerInternal {
private static ColorDisplayManagerInternal sInstance;
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index bac23b3c00f9..1630b0603f3a 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -975,14 +975,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
}
final String msg = getAcquiredString(mContext, acquireInfo, vendorCode);
- if (msg == null) {
- return;
- }
final int clientInfo = acquireInfo == FACE_ACQUIRED_VENDOR
? (vendorCode + FACE_ACQUIRED_VENDOR_BASE) : acquireInfo;
if (mEnrollmentCallback != null) {
mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
- } else if (mAuthenticationCallback != null) {
+ } else if (mAuthenticationCallback != null && msg != null) {
mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
index 9bebbd22c38c..d382eb9310d9 100644
--- a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
+++ b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
@@ -17,6 +17,7 @@ package android.hardware.hdmi;
import android.annotation.Nullable;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import com.android.internal.annotations.VisibleForTesting;
@@ -52,7 +53,7 @@ public final class HdmiAudioSystemClient extends HdmiClient {
@VisibleForTesting(visibility = Visibility.PACKAGE)
public HdmiAudioSystemClient(IHdmiControlService service, @Nullable Handler handler) {
super(service);
- mHandler = handler == null ? new Handler() : handler;
+ mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
}
/** @hide */
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 72a6ffe3aac4..b520d2c14edc 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -388,6 +388,19 @@ public final class HdmiControlManager {
}
/**
+ * Gets whether the system is in system audio mode.
+ *
+ * @hide
+ */
+ public boolean getSystemAudioMode() {
+ try {
+ return mService.getSystemAudioMode();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Listener used to get hotplug event from HDMI port.
*/
public interface HotplugEventListener {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 097a3e3a270a..7d40227f9c7d 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -41,6 +41,7 @@ import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.Region;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -352,7 +353,7 @@ public class InputMethodService extends AbstractInputMethodService {
InputMethodManager mImm;
private InputMethodPrivilegedOperations mPrivOps = new InputMethodPrivilegedOperations();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mTheme = 0;
LayoutInflater mInflater;
@@ -410,7 +411,7 @@ public class InputMethodService extends AbstractInputMethodService {
@GuardedBy("mLock")
private boolean mNotifyUserActionSent;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Insets mTmpInsets = new Insets();
final int[] mTmpLocation = new int[2];
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 49c3dc63e151..61d5a9127743 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -27,6 +27,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
+import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
@@ -2768,7 +2769,7 @@ public class ConnectivityManager {
}
/** {@hide} */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void unregisterNetworkFactory(Messenger messenger) {
try {
mService.unregisterNetworkFactory(messenger);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 77562dbd7bfa..b40f15ae17ba 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -27,6 +27,7 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
@@ -56,13 +57,13 @@ public class LinkAddress implements Parcelable {
/**
* IPv4 or IPv6 address.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private InetAddress address;
/**
* Prefix length.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int prefixLength;
/**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 80517ce28cda..3a792065155e 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -50,7 +51,7 @@ import java.util.StringJoiner;
*/
public final class LinkProperties implements Parcelable {
// The interface described by the network link.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mIfaceName;
private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
private ArrayList<InetAddress> mDnses = new ArrayList<>();
@@ -1136,7 +1137,7 @@ public final class LinkProperties implements Parcelable {
* @return {@code true} if both are identical, {@code false} otherwise.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isIdenticalHttpProxy(LinkProperties target) {
return getHttpProxy() == null ? target.getHttpProxy() == null :
getHttpProxy().equals(target.getHttpProxy());
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 114b423c3184..99bfc140f140 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -19,6 +19,7 @@ package android.net;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.ConnectivityManager.PacketKeepalive;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -352,7 +353,7 @@ public abstract class NetworkAgent extends Handler {
/**
* Called by the bearer code when it has new NetworkInfo data.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void sendNetworkInfo(NetworkInfo networkInfo) {
queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
}
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 9c836c3382db..181cab41e928 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -18,6 +18,7 @@ package android.net;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -289,7 +290,7 @@ public class NetworkFactory extends Handler {
sendMessage(obtainMessage(CMD_CANCEL_REQUEST, networkRequest));
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setScoreFilter(int score) {
sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
}
@@ -307,7 +308,7 @@ public class NetworkFactory extends Handler {
Log.d(LOG_TAG, s);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
pw.println(toString());
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 299b23206dcf..5ab34e9aa6e8 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
+import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.DebugUtils;
@@ -203,7 +204,7 @@ public class NetworkPolicyManager {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void registerListener(INetworkPolicyListener listener) {
try {
mService.registerListener(listener);
@@ -212,7 +213,7 @@ public class NetworkPolicyManager {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void unregisterListener(INetworkPolicyListener listener) {
try {
mService.unregisterListener(listener);
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 3b01b03edd4e..9508217be53f 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -21,6 +21,7 @@ import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.net.NetworkCapabilities.NetCapability;
import android.net.NetworkCapabilities.Transport;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -57,7 +58,7 @@ public class NetworkRequest implements Parcelable {
* Causes CONNECTIVITY_ACTION broadcasts to be sent.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final int legacyType;
/**
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index a00b9a3caeba..9cf582bef1d4 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.os.Process.CLAT_UID;
+
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -828,13 +830,15 @@ public class NetworkStats implements Parcelable {
*
* <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
* packet on the stacked interface, and once as translated to an IPv6 packet on the
- * base interface. For correct stats accounting on the base interface, every 464xlat
- * packet needs to be subtracted from the root UID on the base interface both for tx
- * and rx traffic (http://b/12249687, http:/b/33681750).
+ * base interface. For correct stats accounting on the base interface, if using xt_qtaguid,
+ * every rx 464xlat packet needs to be subtracted from the root UID on the base interface
+ * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto
+ * clat uid should be ignored.
*
* As for eBPF, the per uid stats is collected by different hook, the rx packets on base
- * interface will not be counted. Thus, the adjustment on root uid is only needed in tx
- * direction.
+ * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the
+ * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still
+ * needs to be ignored.
*
* <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
* {@code ConcurrentHashMap}
@@ -862,17 +866,14 @@ public class NetworkStats implements Parcelable {
if (baseIface == null) {
continue;
}
- // Subtract any 464lat traffic seen for the root UID on the current base interface.
- // However, for eBPF, the per uid stats is collected by different hook, the rx packets
- // on base interface will not be counted. Thus, the adjustment on root uid is only
- // needed in tx direction.
+ // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base
+ // interface. As for eBPF, the per uid stats is collected by different hook, the rx
+ // packets on base interface will not be counted.
adjust.iface = baseIface;
if (!useBpfStats) {
adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
adjust.rxPackets = -entry.rxPackets;
}
- adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
- adjust.txPackets = -entry.txPackets;
adjustments.combineValues(adjust);
// For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet
@@ -884,6 +885,9 @@ public class NetworkStats implements Parcelable {
stackedTraffic.setValues(i, entry);
}
+ // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked
+ // v4 interface, so it needs to be removed to avoid double-counting.
+ baseTraffic.removeUids(new int[] {CLAT_UID});
baseTraffic.combineAllValues(adjustments);
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 3e73d3d2d997..37ab9ffb1f5b 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -81,7 +82,7 @@ public final class RouteInfo implements Parcelable {
// Derived data members.
// TODO: remove these.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final boolean mIsHost;
private final boolean mHasGateway;
@@ -265,7 +266,7 @@ public final class RouteInfo implements Parcelable {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean isHost() {
return (mDestination.getAddress() instanceof Inet4Address &&
mDestination.getPrefixLength() == 32) ||
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index 8026d765ee0c..fbc281f26ce8 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -20,6 +20,7 @@ import static android.util.Patterns.GOOD_IRI_CHAR;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import java.util.Locale;
import java.util.regex.Matcher;
@@ -50,7 +51,7 @@ public class WebAddress {
private String mScheme;
@UnsupportedAppUsage
private String mHost;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mPort;
@UnsupportedAppUsage
private String mPath;
diff --git a/core/java/android/net/http/SslError.java b/core/java/android/net/http/SslError.java
index fad6689ed055..b3f2fb79b5c3 100644
--- a/core/java/android/net/http/SslError.java
+++ b/core/java/android/net/http/SslError.java
@@ -17,6 +17,7 @@
package android.net.http;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import java.security.cert.X509Certificate;
/**
@@ -68,7 +69,7 @@ public class SslError {
* The SSL error set bitfield (each individual error is a bit index;
* multiple individual errors can be OR-ed)
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mErrors;
/**
@@ -80,7 +81,7 @@ public class SslError {
/**
* The URL associated with the error set.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final String mUrl;
/**
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index d1b132c6abfa..dd2c0d4f9ee5 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -31,6 +31,8 @@ interface INfcCardEmulation
boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
boolean setDefaultForNextTap(int userHandle, in ComponentName service);
boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
+ boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
+ boolean unsetOffHostForService(int userHandle, in ComponentName service);
AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
List<ApduServiceInfo> getServices(int userHandle, in String category);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 21fed48189eb..e55e0364f5d4 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,7 @@
package android.nfc;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -42,7 +43,9 @@ import android.os.ServiceManager;
import android.util.Log;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* Represents the local NFC adapter.
@@ -322,6 +325,7 @@ public final class NfcAdapter {
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
+ static boolean sHasBeamFeature;
// Final after first constructor, except for
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -369,7 +373,9 @@ public final class NfcAdapter {
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
* to another device.
* @see #setOnNdefPushCompleteCallback
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public interface OnNdefPushCompleteCallback {
/**
* Called on successful NDEF push.
@@ -392,7 +398,9 @@ public final class NfcAdapter {
* content currently visible to the user. Alternatively, you can call {@link
* #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
* same data.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public interface CreateNdefMessageCallback {
/**
* Called to provide a {@link NdefMessage} to push.
@@ -418,7 +426,10 @@ public final class NfcAdapter {
}
- // TODO javadoc
+ /**
+ * @deprecated this feature is deprecated.
+ */
+ @java.lang.Deprecated
public interface CreateBeamUrisCallback {
public Uri[] createBeamUris(NfcEvent event);
}
@@ -446,6 +457,25 @@ public final class NfcAdapter {
public boolean onUnlockAttempted(Tag tag);
}
+ /**
+ * Helper to check if this device has FEATURE_NFC_BEAM, but without using
+ * a context.
+ * Equivalent to
+ * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)
+ */
+ private static boolean hasBeamFeature() {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm == null) {
+ Log.e(TAG, "Cannot get package manager, assuming no Android Beam feature");
+ return false;
+ }
+ try {
+ return pm.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Package manager query failed, assuming no Android Beam feature", e);
+ return false;
+ }
+ }
/**
* Helper to check if this device has FEATURE_NFC, but without using
@@ -488,6 +518,35 @@ public final class NfcAdapter {
}
/**
+ * Return list of Secure Elements which support off host card emulation.
+ *
+ * @return List<String> containing secure elements on the device which supports
+ * off host card emulation. eSE for Embedded secure element,
+ * SIM for UICC and so on.
+ */
+ public @NonNull List<String> getSupportedOffHostSecureElements() {
+ List<String> offHostSE = new ArrayList<String>();
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm == null) {
+ Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature");
+ return offHostSE;
+ }
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC, 0)) {
+ offHostSE.add("SIM");
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE, 0)) {
+ offHostSE.add("eSE");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Package manager query failed, assuming no off-host CE feature", e);
+ offHostSE.clear();
+ return offHostSE;
+ }
+ return offHostSE;
+ }
+
+ /**
* Returns the NfcAdapter for application context,
* or throws if NFC is not available.
* @hide
@@ -496,6 +555,7 @@ public final class NfcAdapter {
public static synchronized NfcAdapter getNfcAdapter(Context context) {
if (!sIsInitialized) {
sHasNfcFeature = hasNfcFeature();
+ sHasBeamFeature = hasBeamFeature();
boolean hasHceFeature = hasNfcHceFeature();
/* is this device meant to have NFC */
if (!sHasNfcFeature && !hasHceFeature) {
@@ -921,12 +981,17 @@ public final class NfcAdapter {
* @param uris an array of Uri(s) to push over Android Beam
* @param activity activity for which the Uri(s) will be pushed
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public void setBeamPushUris(Uri[] uris, Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
if (activity == null) {
throw new NullPointerException("activity cannot be null");
@@ -1003,12 +1068,17 @@ public final class NfcAdapter {
* @param callback callback, or null to disable
* @param activity activity for which the Uri(s) will be pushed
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
if (activity == null) {
throw new NullPointerException("activity cannot be null");
@@ -1087,13 +1157,18 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public void setNdefPushMessage(NdefMessage message, Activity activity,
Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
int targetSdkVersion = getSdkVersion();
try {
@@ -1200,13 +1275,18 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
int targetSdkVersion = getSdkVersion();
try {
@@ -1281,13 +1361,18 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
Activity activity, Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
int targetSdkVersion = getSdkVersion();
try {
@@ -1492,12 +1577,17 @@ public final class NfcAdapter {
* @param activity the current foreground Activity that has registered data to share
* @return whether the Beam animation was successfully invoked
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
public boolean invokeBeam(Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return false;
+ }
}
if (activity == null) {
throw new NullPointerException("activity may not be null.");
@@ -1561,6 +1651,9 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
if (activity == null || message == null) {
throw new NullPointerException();
@@ -1595,6 +1688,9 @@ public final class NfcAdapter {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return;
+ }
}
if (activity == null) {
throw new NullPointerException();
@@ -1668,12 +1764,18 @@ public final class NfcAdapter {
* @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
* @return true if NDEF Push feature is enabled
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @deprecated this feature is deprecated.
*/
+ @java.lang.Deprecated
+
public boolean isNdefPushEnabled() {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
+ if (!sHasBeamFeature) {
+ return false;
+ }
}
try {
return sService.isNdefPushEnabled();
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index e8d801c525e9..911ec8430ddd 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -18,11 +18,10 @@ package android.nfc.cardemulation;
import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
@@ -30,7 +29,6 @@ import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.ResultReceiver;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -69,6 +67,18 @@ public final class ApduServiceInfo implements Parcelable {
final boolean mOnHost;
/**
+ * Offhost reader name.
+ * eg: SIM, eSE etc
+ */
+ String mOffHostName;
+
+ /**
+ * Offhost reader name from manifest file.
+ * Used for unsetOffHostSecureElement()
+ */
+ final String mStaticOffHostName;
+
+ /**
* Mapping from category to static AID group
*/
@UnsupportedAppUsage
@@ -104,15 +114,17 @@ public final class ApduServiceInfo implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+ public ApduServiceInfo(ResolveInfo info, String description,
ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
boolean requiresUnlock, int bannerResource, int uid,
- String settingsActivityName) {
+ String settingsActivityName, String offHost, String staticOffHost) {
this.mService = info;
this.mDescription = description;
this.mStaticAidGroups = new HashMap<String, AidGroup>();
this.mDynamicAidGroups = new HashMap<String, AidGroup>();
- this.mOnHost = onHost;
+ this.mOffHostName = offHost;
+ this.mStaticOffHostName = staticOffHost;
+ this.mOnHost = (offHost == null);
this.mRequiresDeviceUnlock = requiresUnlock;
for (AidGroup aidGroup : staticAidGroups) {
this.mStaticAidGroups.put(aidGroup.category, aidGroup);
@@ -174,6 +186,8 @@ public final class ApduServiceInfo implements Parcelable {
com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
mSettingsActivityName = sa.getString(
com.android.internal.R.styleable.HostApduService_settingsActivity);
+ mOffHostName = null;
+ mStaticOffHostName = mOffHostName;
sa.recycle();
} else {
TypedArray sa = res.obtainAttributes(attrs,
@@ -186,6 +200,16 @@ public final class ApduServiceInfo implements Parcelable {
com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
mSettingsActivityName = sa.getString(
com.android.internal.R.styleable.HostApduService_settingsActivity);
+ mOffHostName = sa.getString(
+ com.android.internal.R.styleable.OffHostApduService_secureElementName);
+ if (mOffHostName != null) {
+ if (mOffHostName.equals("eSE")) {
+ mOffHostName = "eSE1";
+ } else if (mOffHostName.equals("SIM")) {
+ mOffHostName = "SIM1";
+ }
+ }
+ mStaticOffHostName = mOffHostName;
sa.recycle();
}
@@ -289,6 +313,10 @@ public final class ApduServiceInfo implements Parcelable {
mService.serviceInfo.name);
}
+ public String getOffHostSecureElement() {
+ return mOffHostName;
+ }
+
/**
* Returns a consolidated list of AIDs from the AID groups
* registered by this service. Note that if a service has both
@@ -404,6 +432,20 @@ public final class ApduServiceInfo implements Parcelable {
mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
}
+ @UnsupportedAppUsage
+ public void setOffHostSecureElement(String offHost) {
+ mOffHostName = offHost;
+ }
+
+ /**
+ * Resets the off host Secure Element to statically defined
+ * by the service in the manifest file.
+ */
+ @UnsupportedAppUsage
+ public void unsetOffHostSecureElement() {
+ mOffHostName = mStaticOffHostName;
+ }
+
public CharSequence loadLabel(PackageManager pm) {
return mService.loadLabel(pm);
}
@@ -481,6 +523,8 @@ public final class ApduServiceInfo implements Parcelable {
mService.writeToParcel(dest, flags);
dest.writeString(mDescription);
dest.writeInt(mOnHost ? 1 : 0);
+ dest.writeString(mOffHostName);
+ dest.writeString(mStaticOffHostName);
dest.writeInt(mStaticAidGroups.size());
if (mStaticAidGroups.size() > 0) {
dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
@@ -503,6 +547,8 @@ public final class ApduServiceInfo implements Parcelable {
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
String description = source.readString();
boolean onHost = source.readInt() != 0;
+ String offHostName = source.readString();
+ String staticOffHostName = source.readString();
ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
int numStaticGroups = source.readInt();
if (numStaticGroups > 0) {
@@ -517,9 +563,9 @@ public final class ApduServiceInfo implements Parcelable {
int bannerResource = source.readInt();
int uid = source.readInt();
String settingsActivityName = source.readString();
- return new ApduServiceInfo(info, onHost, description, staticAidGroups,
+ return new ApduServiceInfo(info, description, staticAidGroups,
dynamicAidGroups, requiresUnlock, bannerResource, uid,
- settingsActivityName);
+ settingsActivityName, offHostName, staticOffHostName);
}
@Override
@@ -531,6 +577,14 @@ public final class ApduServiceInfo implements Parcelable {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" " + getComponent() +
" (Description: " + getDescription() + ")");
+ if (mOnHost) {
+ pw.println(" On Host Service");
+ } else {
+ pw.println(" Off-host Service");
+ pw.println(" " + "Current off-host SE" + mOffHostName
+ + " static off-host: " + mOffHostName);
+ }
+ pw.println(" Static off-host Secure Element:");
pw.println(" Static AID groups:");
for (AidGroup group : mStaticAidGroups.values()) {
pw.println(" Category: " + group.category);
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 15d02f2e5ddf..01932abfaa9b 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
@@ -345,6 +344,108 @@ public final class CardEmulation {
}
/**
+ * Unsets the off-host Secure Element for the given service.
+ *
+ * <p>Note that this will only remove Secure Element that was dynamically
+ * set using the {@link #setOffHostForService(ComponentName, String)}
+ * and resets it to a value that was statically assigned using manifest.
+ *
+ * <p>Note that you can only unset off-host SE for a service that
+ * is running under the same UID as the caller of this API. Typically
+ * this means you need to call this from the same
+ * package as the service itself, though UIDs can also
+ * be shared between packages using shared UIDs.
+ *
+ * @param service The component name of the service
+ * @return whether the registration was successful.
+ */
+ public boolean unsetOffHostForService(ComponentName service) {
+ NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+ if (adapter == null) {
+ return false;
+ }
+
+ try {
+ return sService.unsetOffHostForService(mContext.getUserId(), service);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.unsetOffHostForService(mContext.getUserId(), service);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Sets the off-host Secure Element for the given service.
+ *
+ * <p>If off-host SE was initially set (either statically
+ * through the manifest, or dynamically by using this API),
+ * it will be replaced with this one. All AIDs registered by
+ * this service will be re-routed to this Secure Element if
+ * successful.
+ *
+ * <p>Note that you can only set off-host SE for a service that
+ * is running under the same UID as the caller of this API. Typically
+ * this means you need to call this from the same
+ * package as the service itself, though UIDs can also
+ * be shared between packages using shared UIDs.
+ *
+ * <p>Registeration will be successful only if the Secure Element
+ * exists on the device.
+ *
+ * @param service The component name of the service
+ * @param offHostSecureElement Secure Element to register the AID to
+ * @return whether the registration was successful.
+ */
+ public boolean setOffHostForService(ComponentName service, String offHostSecureElement) {
+ boolean validSecureElement = false;
+
+ NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+ if (adapter == null || offHostSecureElement == null) {
+ return false;
+ }
+
+ List<String> validSE = adapter.getSupportedOffHostSecureElements();
+ if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
+ || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
+ return false;
+ }
+
+ if (offHostSecureElement.equals("eSE")) {
+ offHostSecureElement = "eSE1";
+ } else if (offHostSecureElement.equals("SIM")) {
+ offHostSecureElement = "SIM1";
+ }
+
+ try {
+ return sService.setOffHostForService(mContext.getUserId(), service,
+ offHostSecureElement);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setOffHostForService(mContext.getUserId(), service,
+ offHostSecureElement);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
* Retrieves the currently registered AIDs for the specified
* category for a service.
*
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
new file mode 100644
index 000000000000..40cbaf75c02d
--- /dev/null
+++ b/core/java/android/os/AppZygote.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.pm.ApplicationInfo;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * AppZygote is responsible for interfacing with an application-specific zygote.
+ *
+ * Application zygotes can pre-load app-specific code and data, and this interface can
+ * be used to spawn isolated services from such an application zygote.
+ *
+ * Note that we'll have only one instance of this per application / uid combination.
+ *
+ * @hide
+ */
+public class AppZygote {
+ private static final String LOG_TAG = "AppZygote";
+
+ private final int mZygoteUid;
+
+ private final Object mLock = new Object();
+
+ /**
+ * Instance that maintains the socket connection to the zygote. This is {@code null} if the
+ * zygote is not running or is not connected.
+ */
+ @GuardedBy("mLock")
+ private ChildZygoteProcess mZygote;
+
+ private final ApplicationInfo mAppInfo;
+
+ public AppZygote(ApplicationInfo appInfo, int zygoteUid) {
+ mAppInfo = appInfo;
+ mZygoteUid = zygoteUid;
+ }
+
+ /**
+ * Returns the zygote process associated with this app zygote.
+ * Creates the process if it's not already running.
+ */
+ public ChildZygoteProcess getProcess() {
+ synchronized (mLock) {
+ if (mZygote != null) return mZygote;
+
+ connectToZygoteIfNeededLocked();
+ return mZygote;
+ }
+ }
+
+ /**
+ * Stops the Zygote and kills the zygote process.
+ */
+ public void stopZygote() {
+ synchronized (mLock) {
+ stopZygoteLocked();
+ }
+ }
+
+ public ApplicationInfo getAppInfo() {
+ return mAppInfo;
+ }
+
+ @GuardedBy("mLock")
+ private void stopZygoteLocked() {
+ if (mZygote != null) {
+ // Close the connection and kill the zygote process. This will not cause
+ // child processes to be killed by itself.
+ mZygote.close();
+ Process.killProcess(mZygote.getPid());
+ mZygote = null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void connectToZygoteIfNeededLocked() {
+ String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi :
+ Build.SUPPORTED_ABIS[0];
+ try {
+ mZygote = Process.zygoteProcess.startChildZygote(
+ "com.android.internal.os.AppZygoteInit",
+ mAppInfo.processName + "_zygote",
+ mZygoteUid,
+ mZygoteUid,
+ null, // gids
+ 0, // runtimeFlags
+ "app_zygote", // seInfo
+ abi, // abi
+ abi, // acceptedAbiList
+ null); // instructionSet
+
+ ZygoteProcess.waitForConnectionToZygote(mZygote.getPrimarySocketAddress());
+ // preload application code in the zygote
+ Log.i(LOG_TAG, "Starting application preload.");
+ mZygote.preloadApp(mAppInfo, abi);
+ Log.i(LOG_TAG, "Application preload done.");
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Error connecting to app zygote", e);
+ stopZygoteLocked();
+ }
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 8904ee61e2e3..a236300a56cf 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -382,6 +382,11 @@ public class Environment {
}
/** {@hide} */
+ public static File getDataStagingDirectory(String volumeUuid) {
+ return new File(getDataDirectory(volumeUuid), "staging");
+ }
+
+ /** {@hide} */
public static File getDataUserCeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user");
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index f3810bddf9c7..d9793097fc3a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -58,7 +58,7 @@ public class GraphicsEnvironment {
private static final boolean DEBUG = false;
private static final String TAG = "GraphicsEnvironment";
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
- private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0";
+ private static final String GUP_WHITELIST_FILENAME = "whitelist.txt";
private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
@@ -482,7 +482,7 @@ public class GraphicsEnvironment {
String applicationPackageName = context.getPackageName();
String devOptInApplicationName = coreSettings.getString(
- Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
+ Settings.Global.GUP_DEV_OPT_IN_APPS);
boolean devOptIn = applicationPackageName.equals(devOptInApplicationName);
boolean whitelisted = onWhitelist(context, driverPackageName, ai.packageName);
if (!devOptIn && !whitelisted) {
@@ -567,22 +567,11 @@ public class GraphicsEnvironment {
private static boolean onWhitelist(Context context, String driverPackageName,
String applicationPackageName) {
- String whitelistName = SystemProperties.get(PROPERTY_GFX_DRIVER_WHITELIST);
-
- // Empty whitelist implies no updatable graphics driver. Typically, the pre-installed
- // updatable graphics driver is supposed to be a place holder and contains no graphics
- // driver and whitelist.
- if (whitelistName == null || whitelistName.isEmpty()) {
- if (DEBUG) {
- Log.w(TAG, "No whitelist found.");
- }
- return false;
- }
try {
Context driverContext = context.createPackageContext(driverPackageName,
Context.CONTEXT_RESTRICTED);
AssetManager assets = driverContext.getAssets();
- InputStream stream = assets.open(whitelistName);
+ InputStream stream = assets.open(GUP_WHITELIST_FILENAME);
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
for (String packageName; (packageName = reader.readLine()) != null; ) {
if (packageName.equals(applicationPackageName)) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 505aec29d438..ee56e3d0ad16 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -111,6 +111,12 @@ public class Process {
public static final int NFC_UID = 1027;
/**
+ * Defines the UID/GID for the clatd process.
+ * @hide
+ * */
+ public static final int CLAT_UID = 1029;
+
+ /**
* Defines the UID/GID for the Bluetooth service process.
* @hide
*/
@@ -199,6 +205,24 @@ public class Process {
public static final int LAST_APPLICATION_UID = 19999;
/**
+ * First uid used for fully isolated sandboxed processes spawned from an app zygote
+ * @hide
+ */
+ public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
+
+ /**
+ * Number of UIDs we allocate per application zygote
+ * @hide
+ */
+ public static final int NUM_UIDS_PER_APP_ZYGOTE = 100;
+
+ /**
+ * Last uid used for fully isolated sandboxed processes spawned from an app zygote
+ * @hide
+ */
+ public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
+
+ /**
* First uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
@@ -644,7 +668,8 @@ public class Process {
/** {@hide} */
public static final boolean isIsolated(int uid) {
uid = UserHandle.getAppId(uid);
- return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
+ return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID)
+ || (uid >= FIRST_APP_ZYGOTE_ISOLATED_UID && uid <= LAST_APP_ZYGOTE_ISOLATED_UID);
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f8feb7b4a693..ad8a4d5645bc 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -138,8 +138,7 @@ public final class UserHandle implements Parcelable {
*/
public static boolean isIsolated(int uid) {
if (uid > 0) {
- final int appId = getAppId(uid);
- return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
+ return Process.isIsolated(uid);
} else {
return false;
}
@@ -294,9 +293,14 @@ public final class UserHandle implements Parcelable {
sb.append('u');
sb.append(getUserId(uid));
final int appId = getAppId(uid);
- if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
- sb.append('i');
- sb.append(appId - Process.FIRST_ISOLATED_UID);
+ if (isIsolated(appId)) {
+ if (appId > Process.FIRST_ISOLATED_UID) {
+ sb.append('i');
+ sb.append(appId - Process.FIRST_ISOLATED_UID);
+ } else {
+ sb.append("ai");
+ sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+ }
} else if (appId >= Process.FIRST_APPLICATION_UID) {
sb.append('a');
sb.append(appId - Process.FIRST_APPLICATION_UID);
@@ -330,9 +334,14 @@ public final class UserHandle implements Parcelable {
pw.print('u');
pw.print(getUserId(uid));
final int appId = getAppId(uid);
- if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
- pw.print('i');
- pw.print(appId - Process.FIRST_ISOLATED_UID);
+ if (isIsolated(appId)) {
+ if (appId > Process.FIRST_ISOLATED_UID) {
+ pw.print('i');
+ pw.print(appId - Process.FIRST_ISOLATED_UID);
+ } else {
+ pw.print("ai");
+ pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+ }
} else if (appId >= Process.FIRST_APPLICATION_UID) {
pw.print('a');
pw.print(appId - Process.FIRST_APPLICATION_UID);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index f136cd6699a7..251c5eebadc4 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.util.Log;
@@ -34,6 +35,7 @@ import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -673,6 +675,36 @@ public class ZygoteProcess {
}
/**
+ * Instructs the zygote to pre-load the application code for the given Application.
+ * Only the app zygote supports this function.
+ * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
+ */
+ public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
+ IOException {
+ synchronized (mLock) {
+ ZygoteState state = openZygoteSocketIfNeeded(abi);
+ state.writer.write("2");
+ state.writer.newLine();
+
+ state.writer.write("--preload-app");
+ state.writer.newLine();
+
+ // Zygote args needs to be strings, so in order to pass ApplicationInfo,
+ // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
+ Parcel parcel = Parcel.obtain();
+ appInfo.writeToParcel(parcel, 0 /* flags */);
+ String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
+ parcel.recycle();
+ state.writer.write(encodedParcelData);
+ state.writer.newLine();
+
+ state.writer.flush();
+
+ return (state.inputStream.readInt() == 0);
+ }
+ }
+
+ /**
* Instructs the zygote to pre-load the classes and native libraries at the given paths
* for the specified abi. Not all zygotes support this function.
*/
@@ -763,6 +795,20 @@ public class ZygoteProcess {
* secondary zygotes that inherit data from the zygote that this object
* communicates with. This returns a new ZygoteProcess representing a connection
* to the newly created zygote. Throws an exception if the zygote cannot be started.
+ *
+ * @param processClass The class to use as the child zygote's main entry
+ * point.
+ * @param niceName A more readable name to use for the process.
+ * @param uid The user-id under which the child zygote will run.
+ * @param gid The group-id under which the child zygote will run.
+ * @param gids Additional group-ids associated with the child zygote process.
+ * @param runtimeFlags Additional flags.
+ * @param seInfo null-ok SELinux information for the child zygote process.
+ * @param abi non-null the ABI of the child zygote
+ * @param acceptedAbiList ABIs this child zygote will accept connections for; this
+ * may be different from <code>abi</code> in case the children
+ * spawned from this Zygote only communicate using ABI-safe methods.
+ * @param instructionSet null-ok the instruction set to use.
*/
public ChildZygoteProcess startChildZygote(final String processClass,
final String niceName,
@@ -770,12 +816,14 @@ public class ZygoteProcess {
int runtimeFlags,
String seInfo,
String abi,
+ String acceptedAbiList,
String instructionSet) {
// Create an unguessable address in the global abstract namespace.
final LocalSocketAddress serverAddress = new LocalSocketAddress(
processClass + "/" + UUID.randomUUID().toString());
- final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};
+ final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
+ Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList};
Process.ProcessStartResult result;
try {
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 7b6c97132b5c..828f1c304ccb 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -66,7 +67,7 @@ public class DiskInfo implements Parcelable {
this.flags = flags;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public DiskInfo(Parcel parcel) {
id = parcel.readString();
flags = parcel.readInt();
@@ -196,7 +197,7 @@ public class DiskInfo implements Parcelable {
return id.hashCode();
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() {
@Override
public DiskInfo createFromParcel(Parcel in) {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9594a713a506..735f4f253594 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1540,6 +1540,7 @@ public class StorageManager {
}
/** {@hide} */
+ @SystemApi
@TestApi
public static boolean hasIsolatedStorage() {
// Prefer to use snapshot for current boot when available
diff --git a/core/java/android/permission/IRuntimePermissionPresenter.aidl b/core/java/android/permission/IPermissionController.aidl
index e95428ab2b02..38951d5466c7 100644
--- a/core/java/android/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -19,11 +19,11 @@ package android.permission;
import android.os.RemoteCallback;
/**
- * Interface for communication with the permission presenter service.
+ * Interface for system apps to communication with the permission controller.
*
* @hide
*/
-oneway interface IRuntimePermissionPresenter {
+oneway interface IPermissionController {
void getAppPermissions(String packageName, in RemoteCallback callback);
void revokeRuntimePermission(String packageName, String permissionName);
void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
diff --git a/core/java/android/permission/RuntimePermissionPresenter.java b/core/java/android/permission/PermissionControllerManager.java
index c607e3fb309c..66e8666a8a70 100644
--- a/core/java/android/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -16,13 +16,16 @@
package android.permission;
-import static android.permission.RuntimePermissionPresenterService.SERVICE_INTERFACE;
+import static android.permission.PermissionControllerService.SERVICE_INTERFACE;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -34,7 +37,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
import com.android.internal.infra.AbstractRemoteService;
@@ -42,29 +44,24 @@ import java.util.Collections;
import java.util.List;
/**
- * This class provides information about runtime permissions for a specific
- * app or all apps. This information is dedicated for presentation purposes
- * and does not necessarily reflect the individual permissions requested/
- * granted to an app as the platform may be grouping permissions to improve
- * presentation and help the user make an informed choice. For example, all
- * runtime permissions in the same permission group may be presented as a
- * single permission in the UI.
+ * Interface for communicating with the permission controller from system apps. All UI operations
+ * regarding permissions and any changes to the permission state should flow through this
+ * interface.
*
* @hide
*/
-public final class RuntimePermissionPresenter {
- private static final String TAG = "RuntimePermPresenter";
+@SystemService(Context.PERMISSION_CONTROLLER_SERVICE)
+public final class PermissionControllerManager {
+ private static final String TAG = PermissionControllerManager.class.getSimpleName();
/**
* The key for retrieving the result from the returned bundle.
- *
- * @hide
*/
public static final String KEY_RESULT =
- "android.permission.RuntimePermissionPresenter.key.result";
+ "android.permission.PermissionControllerManager.key.result";
/**
- * Listener for delivering the result of {@link #getAppPermissions}.
+ * Callback for delivering the result of {@link #getAppPermissions}.
*/
public interface OnGetAppPermissionResultCallback {
/**
@@ -77,7 +74,7 @@ public final class RuntimePermissionPresenter {
}
/**
- * Listener for delivering the result of {@link #countPermissionApps}.
+ * Callback for delivering the result of {@link #countPermissionApps}.
*/
public interface OnCountPermissionAppsResultCallback {
/**
@@ -89,29 +86,9 @@ public final class RuntimePermissionPresenter {
void onCountPermissionApps(int numApps);
}
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static RuntimePermissionPresenter sInstance;
-
private final RemoteService mRemoteService;
- /**
- * Gets the singleton runtime permission presenter.
- *
- * @param context Context for accessing resources.
- * @return The singleton instance.
- */
- public static RuntimePermissionPresenter getInstance(@NonNull Context context) {
- synchronized (sLock) {
- if (sInstance == null) {
- sInstance = new RuntimePermissionPresenter(context.getApplicationContext());
- }
- return sInstance;
- }
- }
-
- private RuntimePermissionPresenter(@NonNull Context context) {
+ public PermissionControllerManager(@NonNull Context context) {
Intent intent = new Intent(SERVICE_INTERFACE);
intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
@@ -127,6 +104,7 @@ public final class RuntimePermissionPresenter {
* @param callback Callback to receive the result.
* @param handler Handler on which to invoke the callback.
*/
+ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
public void getAppPermissions(@NonNull String packageName,
@NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
checkNotNull(packageName);
@@ -142,6 +120,7 @@ public final class RuntimePermissionPresenter {
* @param packageName The package for which to revoke
* @param permissionName The permission to revoke
*/
+ @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
public void revokeRuntimePermission(@NonNull String packageName,
@NonNull String permissionName) {
checkNotNull(packageName);
@@ -160,6 +139,7 @@ public final class RuntimePermissionPresenter {
* @param callback Callback to receive the result
* @param handler Handler on which to invoke the callback
*/
+ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
public void countPermissionApps(@NonNull List<String> permissionNames,
boolean countOnlyGranted, boolean countSystem,
@NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) {
@@ -175,8 +155,7 @@ public final class RuntimePermissionPresenter {
* A connection to the remote service
*/
static final class RemoteService extends
- AbstractMultiplePendingRequestsRemoteService<RemoteService,
- IRuntimePermissionPresenter> {
+ AbstractMultiplePendingRequestsRemoteService<RemoteService, IPermissionController> {
private static final long UNBIND_TIMEOUT_MILLIS = 10000;
private static final long MESSAGE_TIMEOUT_MILLIS = 30000;
@@ -200,9 +179,8 @@ public final class RuntimePermissionPresenter {
}
@Override
- protected @NonNull IRuntimePermissionPresenter getServiceInterface(
- @NonNull IBinder binder) {
- return IRuntimePermissionPresenter.Stub.asInterface(binder);
+ protected @NonNull IPermissionController getServiceInterface(@NonNull IBinder binder) {
+ return IPermissionController.Stub.asInterface(binder);
}
@Override
@@ -217,13 +195,12 @@ public final class RuntimePermissionPresenter {
@Override
public void scheduleRequest(@NonNull PendingRequest<RemoteService,
- IRuntimePermissionPresenter> pendingRequest) {
+ IPermissionController> pendingRequest) {
super.scheduleRequest(pendingRequest);
}
@Override
- public void scheduleAsyncRequest(
- @NonNull AsyncRequest<IRuntimePermissionPresenter> request) {
+ public void scheduleAsyncRequest(@NonNull AsyncRequest<IPermissionController> request) {
super.scheduleAsyncRequest(request);
}
}
@@ -232,7 +209,7 @@ public final class RuntimePermissionPresenter {
* Request for {@link #getAppPermissions}
*/
private static final class PendingGetAppPermissionRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
+ AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
private final @NonNull String mPackageName;
private final @NonNull OnGetAppPermissionResultCallback mCallback;
@@ -282,7 +259,7 @@ public final class RuntimePermissionPresenter {
* Request for {@link #revokeRuntimePermission}
*/
private static final class PendingRevokeAppPermissionRequest
- implements AbstractRemoteService.AsyncRequest<IRuntimePermissionPresenter> {
+ implements AbstractRemoteService.AsyncRequest<IPermissionController> {
private final @NonNull String mPackageName;
private final @NonNull String mPermissionName;
@@ -293,7 +270,7 @@ public final class RuntimePermissionPresenter {
}
@Override
- public void run(IRuntimePermissionPresenter remoteInterface) {
+ public void run(IPermissionController remoteInterface) {
try {
remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
} catch (RemoteException e) {
@@ -306,7 +283,7 @@ public final class RuntimePermissionPresenter {
* Request for {@link #countPermissionApps}
*/
private static final class PendingCountPermissionAppsRequest extends
- AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
+ AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
private final @NonNull List<String> mPermissionNames;
private final @NonNull OnCountPermissionAppsResultCallback mCallback;
private final boolean mCountOnlyGranted;
diff --git a/core/java/android/permission/RuntimePermissionPresenterService.java b/core/java/android/permission/PermissionControllerService.java
index 81ec7bed19af..5dad07178e53 100644
--- a/core/java/android/permission/RuntimePermissionPresenterService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkCollectionElementsNot
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
@@ -33,26 +34,21 @@ import android.os.RemoteCallback;
import java.util.List;
/**
- * This service presents information regarding runtime permissions that is
- * used for presenting them in the UI. Runtime permissions are presented as
- * a single permission in the UI but may be composed of several individual
- * permissions.
+ * This service is meant to be implemented by the app controlling permissions.
*
- * @see RuntimePermissionPresenter
- * @see RuntimePermissionPresentationInfo
+ * @see PermissionController
*
* @hide
*/
@SystemApi
-public abstract class RuntimePermissionPresenterService extends Service {
+public abstract class PermissionControllerService extends Service {
/**
* The {@link Intent} action that must be declared as handled by a service
* in its manifest for the system to recognize it as a runtime permission
* presenter service.
*/
- public static final String SERVICE_INTERFACE =
- "android.permission.RuntimePermissionPresenterService";
+ public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
// No need for locking - always set first and never modified
private Handler mHandler;
@@ -96,16 +92,17 @@ public abstract class RuntimePermissionPresenterService extends Service {
@Override
public final IBinder onBind(Intent intent) {
- return new IRuntimePermissionPresenter.Stub() {
+ return new IPermissionController.Stub() {
@Override
public void getAppPermissions(String packageName, RemoteCallback callback) {
checkNotNull(packageName, "packageName");
checkNotNull(callback, "callback");
+ enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
mHandler.sendMessage(
- obtainMessage(
- RuntimePermissionPresenterService::getAppPermissions,
- RuntimePermissionPresenterService.this, packageName, callback));
+ obtainMessage(PermissionControllerService::getAppPermissions,
+ PermissionControllerService.this, packageName, callback));
}
@Override
@@ -113,11 +110,11 @@ public abstract class RuntimePermissionPresenterService extends Service {
checkNotNull(packageName, "packageName");
checkNotNull(permissionName, "permissionName");
+ enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+
mHandler.sendMessage(
- obtainMessage(
- RuntimePermissionPresenterService::onRevokeRuntimePermission,
- RuntimePermissionPresenterService.this, packageName,
- permissionName));
+ obtainMessage(PermissionControllerService::onRevokeRuntimePermission,
+ PermissionControllerService.this, packageName, permissionName));
}
@Override
@@ -126,11 +123,12 @@ public abstract class RuntimePermissionPresenterService extends Service {
checkCollectionElementsNotNull(permissionNames, "permissionNames");
checkNotNull(callback, "callback");
+ enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
mHandler.sendMessage(
- obtainMessage(
- RuntimePermissionPresenterService::countPermissionApps,
- RuntimePermissionPresenterService.this, permissionNames,
- countOnlyGranted, countSystem, callback));
+ obtainMessage(PermissionControllerService::countPermissionApps,
+ PermissionControllerService.this, permissionNames, countOnlyGranted,
+ countSystem, callback));
}
};
}
@@ -139,7 +137,7 @@ public abstract class RuntimePermissionPresenterService extends Service {
List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
if (permissions != null && !permissions.isEmpty()) {
Bundle result = new Bundle();
- result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, permissions);
+ result.putParcelableList(PermissionControllerManager.KEY_RESULT, permissions);
callback.sendResult(result);
} else {
callback.sendResult(null);
@@ -151,7 +149,7 @@ public abstract class RuntimePermissionPresenterService extends Service {
int numApps = onCountPermissionApps(permissionNames, countOnlyGranted, countSystem);
Bundle result = new Bundle();
- result.putInt(RuntimePermissionPresenter.KEY_RESULT, numApps);
+ result.putInt(PermissionControllerManager.KEY_RESULT, numApps);
callback.sendResult(result);
}
}
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 2b3f0f525904..8d568c84b915 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -30,6 +30,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
+import android.permission.PermissionControllerService;
import java.util.List;
@@ -43,7 +44,7 @@ import java.util.List;
*
* @hide
*
- * @deprecated use {@link android.permission.RuntimePermissionPresenterService} instead
+ * @deprecated use {@link PermissionControllerService} instead
*/
@Deprecated
@SystemApi
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index e5fd29cc09b1..b348da45e2d6 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -409,6 +409,15 @@ public final class Downloads {
public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
/**
+ * Similar to {@link #COLUMN_MEDIAPROVIDER_URI}, except this cannot be updated/queried
+ * by apps and will be the source of truth when updating/deleting download entries in
+ * MediaProvider database.
+ *
+ * <P>Type: TEXT</P>
+ */
+ public static final String COLUMN_MEDIASTORE_URI = "mediastore_uri";
+
+ /**
* The column that is used to remember whether the media scanner was invoked.
* It can take the values: null or 0(not scanned), 1(scanned), 2 (not scannable).
* <P>Type: TEXT</P>
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 457453fd210b..cdbc9790c952 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -17,6 +17,7 @@
package android.provider;
import android.annotation.BytesLong;
+import android.annotation.DurationMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -55,6 +56,7 @@ import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.service.media.CameraPrewarmService;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -131,6 +133,8 @@ public final class MediaStore {
/** {@hide} */
public static final String PARAM_INCLUDE_PENDING = "includePending";
/** {@hide} */
+ public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
+ /** {@hide} */
public static final String PARAM_PROGRESS = "progress";
/** {@hide} */
public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";
@@ -485,12 +489,29 @@ public final class MediaStore {
* By default no pending items are returned.
*
* @see MediaColumns#IS_PENDING
+ * @see MediaStore#setIncludePending(Uri)
+ * @see MediaStore#createPending(Context, PendingParams)
*/
public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_PENDING, "1").build();
}
/**
+ * Update the given {@link Uri} to also include any trashed media items from
+ * calls such as
+ * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
+ * By default no trashed items are returned.
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#trash(Context, Uri)
+ * @see MediaStore#untrash(Context, Uri)
+ */
+ public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
+ return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
+ }
+
+ /**
* Update the given {@link Uri} to indicate that the caller requires the
* original file contents when calling
* {@link ContentResolver#openFileDescriptor(Uri, String)}.
@@ -516,6 +537,9 @@ public final class MediaStore {
*
* @return token which can be passed to {@link #openPending(Context, Uri)}
* to work with this pending item.
+ * @see MediaColumns#IS_PENDING
+ * @see MediaStore#setIncludePending(Uri)
+ * @see MediaStore#createPending(Context, PendingParams)
*/
public static @NonNull Uri createPending(@NonNull Context context,
@NonNull PendingParams params) {
@@ -572,6 +596,8 @@ public final class MediaStore {
this.insertValues.put(MediaColumns.DATE_ADDED, now);
this.insertValues.put(MediaColumns.DATE_MODIFIED, now);
this.insertValues.put(MediaColumns.IS_PENDING, 1);
+ this.insertValues.put(MediaColumns.DATE_EXPIRES,
+ (System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS) / 1000);
}
/**
@@ -696,6 +722,7 @@ public final class MediaStore {
public @NonNull Uri publish() {
final ContentValues values = new ContentValues();
values.put(MediaColumns.IS_PENDING, 0);
+ values.putNull(MediaColumns.DATE_EXPIRES);
mContext.getContentResolver().update(mUri, values, null, null);
return mUri;
}
@@ -717,6 +744,67 @@ public final class MediaStore {
}
/**
+ * Mark the given item as being "trashed", meaning it should be deleted at
+ * some point in the future. This is a more gentle operation than simply
+ * calling {@link ContentResolver#delete(Uri, String, String[])}, which
+ * would take effect immediately.
+ * <p>
+ * This method preserves trashed items for at least 48 hours before erasing
+ * them, giving the user a chance to untrash the item.
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#trash(Context, Uri)
+ * @see MediaStore#untrash(Context, Uri)
+ */
+ public static void trash(@NonNull Context context, @NonNull Uri uri) {
+ trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
+ }
+
+ /**
+ * Mark the given item as being "trashed", meaning it should be deleted at
+ * some point in the future. This is a more gentle operation than simply
+ * calling {@link ContentResolver#delete(Uri, String, String[])}, which
+ * would take effect immediately.
+ * <p>
+ * This method preserves trashed items for at least the given timeout before
+ * erasing them, giving the user a chance to untrash the item.
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#trash(Context, Uri)
+ * @see MediaStore#untrash(Context, Uri)
+ */
+ public static void trash(@NonNull Context context, @NonNull Uri uri,
+ @DurationMillisLong long timeoutMillis) {
+ if (timeoutMillis < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ final ContentValues values = new ContentValues();
+ values.put(MediaColumns.IS_TRASHED, 1);
+ values.put(MediaColumns.DATE_EXPIRES,
+ (System.currentTimeMillis() + timeoutMillis) / 1000);
+ context.getContentResolver().update(uri, values, null, null);
+ }
+
+ /**
+ * Mark the given item as being "untrashed", meaning it should no longer be
+ * deleted as previously requested through {@link #trash(Context, Uri)}.
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#trash(Context, Uri)
+ * @see MediaStore#untrash(Context, Uri)
+ */
+ public static void untrash(@NonNull Context context, @NonNull Uri uri) {
+ final ContentValues values = new ContentValues();
+ values.put(MediaColumns.IS_TRASHED, 0);
+ values.putNull(MediaColumns.DATE_EXPIRES);
+ context.getContentResolver().update(uri, values, null, null);
+ }
+
+ /**
* Common fields for most MediaProvider tables
*/
public interface MediaColumns extends BaseColumns {
@@ -821,12 +909,34 @@ public final class MediaStore {
* <p>
* Type: BOOLEAN
*
+ * @see MediaColumns#IS_PENDING
+ * @see MediaStore#setIncludePending(Uri)
* @see MediaStore#createPending(Context, PendingParams)
- * @see MediaStore#PARAM_INCLUDE_PENDING
*/
public static final String IS_PENDING = "is_pending";
/**
+ * Flag indicating if a media item is trashed.
+ * <p>
+ * Type: BOOLEAN
+ *
+ * @see MediaColumns#IS_TRASHED
+ * @see MediaStore#setIncludeTrashed(Uri)
+ * @see MediaStore#trash(Context, Uri)
+ * @see MediaStore#untrash(Context, Uri)
+ */
+ public static final String IS_TRASHED = "is_trashed";
+
+ /**
+ * The time the file should be considered expired. Units are seconds
+ * since 1970. Typically only meaningful in the context of
+ * {@link #IS_PENDING} or {@link #IS_TRASHED}.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String DATE_EXPIRES = "date_expires";
+
+ /**
* The width of the image/video in pixels.
*/
public static final String WIDTH = "width";
@@ -915,6 +1025,11 @@ public final class MediaStore {
return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("dir").build();
}
+ /** @hide */
+ public static final Uri getContentUriForPath(String path) {
+ return getContentUri(getVolumeNameForPath(path));
+ }
+
/**
* Fields for master table for all media files.
* Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
@@ -1021,6 +1136,13 @@ public final class MediaStore {
* Type: TEXT
*/
String REFERER_URI = "referer_uri";
+
+ /**
+ * The description of the download.
+ * <p>
+ * Type: Text
+ */
+ String DESCRIPTION = "description";
}
/**
@@ -1251,18 +1373,32 @@ public final class MediaStore {
public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
/**
- * The bucket id of the image. This is a read-only property that
- * is automatically computed from the DATA column.
- * <P>Type: TEXT</P>
+ * The primary bucket ID of this media item. This can be useful to
+ * present the user a first-level clustering of related media items.
+ * This is a read-only column that is automatically computed.
+ * <p>
+ * Type: INTEGER
*/
public static final String BUCKET_ID = "bucket_id";
/**
- * The bucket display name of the image. This is a read-only property that
- * is automatically computed from the DATA column.
- * <P>Type: TEXT</P>
+ * The primary bucket display name of this media item. This can be
+ * useful to present the user a first-level clustering of related
+ * media items. This is a read-only column that is automatically
+ * computed.
+ * <p>
+ * Type: TEXT
*/
public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
+
+ /**
+ * The secondary bucket ID of this media item. This can be useful to
+ * present the user a second-level clustering of related media
+ * items. This is a read-only column that is automatically computed.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
}
public static final class Media implements ImageColumns {
@@ -1338,7 +1474,7 @@ public final class MediaStore {
public static final String insertImage(ContentResolver cr, Bitmap source,
String title, String description) {
ContentValues values = new ContentValues();
- values.put(Images.Media.TITLE, title);
+ values.put(Images.Media.DISPLAY_NAME, title);
values.put(Images.Media.DESCRIPTION, description);
values.put(Images.Media.MIME_TYPE, "image/jpeg");
@@ -2500,20 +2636,34 @@ public final class MediaStore {
public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
/**
- * The bucket id of the video. This is a read-only property that
- * is automatically computed from the DATA column.
- * <P>Type: TEXT</P>
+ * The primary bucket ID of this media item. This can be useful to
+ * present the user a first-level clustering of related media items.
+ * This is a read-only column that is automatically computed.
+ * <p>
+ * Type: INTEGER
*/
public static final String BUCKET_ID = "bucket_id";
/**
- * The bucket display name of the video. This is a read-only property that
- * is automatically computed from the DATA column.
- * <P>Type: TEXT</P>
+ * The primary bucket display name of this media item. This can be
+ * useful to present the user a first-level clustering of related
+ * media items. This is a read-only column that is automatically
+ * computed.
+ * <p>
+ * Type: TEXT
*/
public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
/**
+ * The secondary bucket ID of this media item. This can be useful to
+ * present the user a second-level clustering of related media
+ * items. This is a read-only column that is automatically computed.
+ * <p>
+ * Type: INTEGER
+ */
+ public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
+
+ /**
* The bookmark for the video. Time in ms. Represents the location in the video that the
* video should start playing at the next time it is opened. If the value is null or
* out of the range 0..DURATION-1 then the video should start playing from the
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d93985c8ec3d..bb1784af6c85 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7957,6 +7957,15 @@ public final class Settings {
"night_display_last_activated_time";
/**
+ * Control whether display white balance is currently enabled.
+ * @hide
+ */
+ public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled";
+
+ private static final Validator DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
+ /**
* Names of the service components that the current user has explicitly allowed to
* be a VR mode listener, separated by ':'.
*
@@ -8405,6 +8414,7 @@ public final class Settings {
NIGHT_DISPLAY_CUSTOM_END_TIME,
NIGHT_DISPLAY_COLOR_TEMPERATURE,
NIGHT_DISPLAY_AUTO_MODE,
+ DISPLAY_WHITE_BALANCE_ENABLED,
SYNC_PARENT_SOUNDS,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
SWIPE_UP_TO_SWITCH_APPS_ENABLED,
@@ -8552,6 +8562,7 @@ public final class Settings {
VALIDATORS.put(NIGHT_DISPLAY_COLOR_TEMPERATURE,
NIGHT_DISPLAY_COLOR_TEMPERATURE_VALIDATOR);
VALIDATORS.put(NIGHT_DISPLAY_AUTO_MODE, NIGHT_DISPLAY_AUTO_MODE_VALIDATOR);
+ VALIDATORS.put(DISPLAY_WHITE_BALANCE_ENABLED, DISPLAY_WHITE_BALANCE_ENABLED_VALIDATOR);
VALIDATORS.put(SYNC_PARENT_SOUNDS, SYNC_PARENT_SOUNDS_VALIDATOR);
VALIDATORS.put(CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED_VALIDATOR);
@@ -11971,11 +11982,16 @@ public final class Settings {
"angle_gl_driver_selection_values";
/**
- * App that is selected to use updated graphics driver.
+ * Apps that are selected to use Game Update Package.
* @hide
*/
- public static final String UPDATED_GFX_DRIVER_DEV_OPT_IN_APP =
- "updated_gfx_driver_dev_opt_in_app";
+ public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps";
+
+ /**
+ * Apps on the black list that are forbidden to useGame Update Package.
+ * @hide
+ */
+ public static final String GUP_BLACK_LIST = "gup_black_list";
/**
* Ordered GPU debug layer list for Vulkan
@@ -14059,11 +14075,10 @@ public final class Settings {
try {
Bundle arg = new Bundle();
arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
- arg.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, resetMode);
+ arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode);
if (prefix != null) {
arg.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
}
- arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode);
IContentProvider cp = sProviderHolder.getProvider(resolver);
cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
CALL_METHOD_RESET_CONFIG, null, arg);
diff --git a/core/java/android/service/autofill/CompositeUserData.java b/core/java/android/service/autofill/CompositeUserData.java
new file mode 100644
index 000000000000..2df4ddf7f8ee
--- /dev/null
+++ b/core/java/android/service/autofill/CompositeUserData.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Holds both a generic and package-specific userData used for
+ * <a href="AutofillService.html#FieldClassification">field classification</a>.
+ *
+ * @hide
+ */
+@TestApi
+public final class CompositeUserData implements FieldClassificationUserData, Parcelable {
+
+ private final UserData mGenericUserData;
+ private final UserData mPackageUserData;
+
+ private final String[] mCategories;
+ private final String[] mValues;
+
+ public CompositeUserData(@Nullable UserData genericUserData,
+ @NonNull UserData packageUserData) {
+ mGenericUserData = genericUserData;
+ mPackageUserData = packageUserData;
+
+ final String[] packageCategoryIds = mPackageUserData.getCategoryIds();
+ final String[] packageValues = mPackageUserData.getValues();
+
+ final ArrayList<String> categoryIds = new ArrayList<>(packageCategoryIds.length);
+ final ArrayList<String> values = new ArrayList<>(packageValues.length);
+
+ Collections.addAll(categoryIds, packageCategoryIds);
+ Collections.addAll(values, packageValues);
+
+ if (mGenericUserData != null) {
+ final String[] genericCategoryIds = mGenericUserData.getCategoryIds();
+ final String[] genericValues = mGenericUserData.getValues();
+ final int size = mGenericUserData.getCategoryIds().length;
+ for (int i = 0; i < size; i++) {
+ if (!categoryIds.contains(genericCategoryIds[i])) {
+ categoryIds.add(genericCategoryIds[i]);
+ values.add(genericValues[i]);
+ }
+ }
+ }
+
+ mCategories = new String[categoryIds.size()];
+ categoryIds.toArray(mCategories);
+ mValues = new String[values.size()];
+ values.toArray(mValues);
+ }
+
+ @Nullable
+ @Override
+ public String getFieldClassificationAlgorithm() {
+ final String packageDefaultAlgo = mPackageUserData.getFieldClassificationAlgorithm();
+ if (packageDefaultAlgo != null) {
+ return packageDefaultAlgo;
+ } else {
+ return mGenericUserData == null ? null :
+ mGenericUserData.getFieldClassificationAlgorithm();
+ }
+ }
+
+ @Override
+ public Bundle getDefaultFieldClassificationArgs() {
+ final Bundle packageDefaultArgs = mPackageUserData.getDefaultFieldClassificationArgs();
+ if (packageDefaultArgs != null) {
+ return packageDefaultArgs;
+ } else {
+ return mGenericUserData == null ? null :
+ mGenericUserData.getDefaultFieldClassificationArgs();
+ }
+ }
+
+ @Nullable
+ @Override
+ public String getFieldClassificationAlgorithmForCategory(@NonNull String categoryId) {
+ Preconditions.checkNotNull(categoryId);
+ final ArrayMap<String, String> categoryAlgorithms = getFieldClassificationAlgorithms();
+ if (categoryAlgorithms == null || !categoryAlgorithms.containsKey(categoryId)) {
+ return null;
+ }
+ return categoryAlgorithms.get(categoryId);
+ }
+
+ @Override
+ public ArrayMap<String, String> getFieldClassificationAlgorithms() {
+ final ArrayMap<String, String> packageAlgos = mPackageUserData
+ .getFieldClassificationAlgorithms();
+ final ArrayMap<String, String> genericAlgos = mGenericUserData == null ? null :
+ mGenericUserData.getFieldClassificationAlgorithms();
+
+ ArrayMap<String, String> categoryAlgorithms = null;
+ if (packageAlgos != null || genericAlgos != null) {
+ categoryAlgorithms = new ArrayMap<>();
+ if (genericAlgos != null) {
+ categoryAlgorithms.putAll(genericAlgos);
+ }
+ if (packageAlgos != null) {
+ categoryAlgorithms.putAll(packageAlgos);
+ }
+ }
+
+ return categoryAlgorithms;
+ }
+
+ @Override
+ public ArrayMap<String, Bundle> getFieldClassificationArgs() {
+ final ArrayMap<String, Bundle> packageArgs = mPackageUserData.getFieldClassificationArgs();
+ final ArrayMap<String, Bundle> genericArgs = mGenericUserData == null ? null :
+ mGenericUserData.getFieldClassificationArgs();
+
+ ArrayMap<String, Bundle> categoryArgs = null;
+ if (packageArgs != null || genericArgs != null) {
+ categoryArgs = new ArrayMap<>();
+ if (genericArgs != null) {
+ categoryArgs.putAll(genericArgs);
+ }
+ if (packageArgs != null) {
+ categoryArgs.putAll(packageArgs);
+ }
+ }
+
+ return categoryArgs;
+ }
+
+ @Override
+ public String[] getCategoryIds() {
+ return mCategories;
+ }
+
+ @Override
+ public String[] getValues() {
+ return mValues;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ // OK to print UserData because UserData.toString() is PII-aware
+ final StringBuilder builder = new StringBuilder("genericUserData=")
+ .append(mGenericUserData)
+ .append(", packageUserData=").append(mPackageUserData);
+ return builder.toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mGenericUserData, 0);
+ parcel.writeParcelable(mPackageUserData, 0);
+ }
+
+ public static final Parcelable.Creator<CompositeUserData> CREATOR =
+ new Parcelable.Creator<CompositeUserData>() {
+ @Override
+ public CompositeUserData createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final UserData genericUserData = parcel.readParcelable(null);
+ final UserData packageUserData = parcel.readParcelable(null);
+ return new CompositeUserData(genericUserData, packageUserData);
+ }
+
+ @Override
+ public CompositeUserData[] newArray(int size) {
+ return new CompositeUserData[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/FieldClassificationUserData.java b/core/java/android/service/autofill/FieldClassificationUserData.java
new file mode 100644
index 000000000000..3d6cac4dca0c
--- /dev/null
+++ b/core/java/android/service/autofill/FieldClassificationUserData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import android.os.Bundle;
+import android.util.ArrayMap;
+
+/**
+ * Class used to define a generic UserData for field classification
+ *
+ * @hide
+ */
+public interface FieldClassificationUserData {
+ /**
+ * Gets the name of the default algorithm that is used to calculate
+ * {@link FieldClassification.Match#getScore()} match scores}.
+ */
+ String getFieldClassificationAlgorithm();
+
+ /**
+ * Gets the default field classification args.
+ */
+ Bundle getDefaultFieldClassificationArgs();
+
+ /**
+ * Gets the name of the field classification algorithm for a specific category.
+ *
+ * @param categoryId id of the specific category.
+ */
+ String getFieldClassificationAlgorithmForCategory(String categoryId);
+
+ /**
+ * Gets all field classification algorithms for specific categories.
+ */
+ ArrayMap<String, String> getFieldClassificationAlgorithms();
+
+ /**
+ * Gets all field classification args for specific categories.
+ */
+ ArrayMap<String, Bundle> getFieldClassificationArgs();
+
+ /**
+ * Gets all category ids
+ */
+ String[] getCategoryIds();
+
+ /**
+ * Gets all string values for field classification
+ */
+ String[] getValues();
+}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index d408e9a6c3b1..93ee8c33195b 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -516,6 +516,9 @@ public final class FillResponse implements Parcelable {
/**
* Sets a specific {@link UserData} for field classification for this request only.
*
+ * <p>Any fields in this UserData will override corresponding fields in the generic
+ * UserData object
+ *
* @return this builder
* @throws IllegalStateException if the FillResponse
* {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)
diff --git a/core/java/android/service/autofill/UserData.java b/core/java/android/service/autofill/UserData.java
index 37f192366f81..a793e09e79f1 100644
--- a/core/java/android/service/autofill/UserData.java
+++ b/core/java/android/service/autofill/UserData.java
@@ -48,7 +48,7 @@ import java.util.ArrayList;
* Defines the user data used for
* <a href="AutofillService.html#FieldClassification">field classification</a>.
*/
-public final class UserData implements Parcelable {
+public final class UserData implements FieldClassificationUserData, Parcelable {
private static final String TAG = "UserData";
@@ -86,11 +86,13 @@ public final class UserData implements Parcelable {
* {@link Match#getScore()} match scores}.
*/
@Nullable
+ @Override
public String getFieldClassificationAlgorithm() {
return mDefaultAlgorithm;
}
/** @hide */
+ @Override
public Bundle getDefaultFieldClassificationArgs() {
return mDefaultArgs;
}
@@ -104,6 +106,7 @@ public final class UserData implements Parcelable {
* @return String name of algorithm, null if none found.
*/
@Nullable
+ @Override
public String getFieldClassificationAlgorithmForCategory(@NonNull String categoryId) {
Preconditions.checkNotNull(categoryId);
if (mCategoryAlgorithms == null || !mCategoryAlgorithms.containsKey(categoryId)) {
@@ -120,22 +123,26 @@ public final class UserData implements Parcelable {
}
/** @hide */
+ @Override
public String[] getCategoryIds() {
return mCategoryIds;
}
/** @hide */
+ @Override
public String[] getValues() {
return mValues;
}
/** @hide */
@TestApi
+ @Override
public ArrayMap<String, String> getFieldClassificationAlgorithms() {
return mCategoryAlgorithms;
}
/** @hide */
+ @Override
public ArrayMap<String, Bundle> getFieldClassificationArgs() {
return mCategoryArgs;
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 6d2f85679cff..0e63cd37f3f2 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -98,7 +98,7 @@ import java.util.List;
*/
public abstract class NotificationListenerService extends Service {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String TAG = getClass().getSimpleName();
/**
@@ -294,7 +294,7 @@ public abstract class NotificationListenerService extends Service {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected INotificationManager mNoMan;
/**
@@ -516,7 +516,7 @@ public abstract class NotificationListenerService extends Service {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 84826e0f6824..ad10cc91f34c 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -22,6 +22,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -35,7 +36,7 @@ public class StatusBarNotification implements Parcelable {
private final String pkg;
@UnsupportedAppUsage
private final int id;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String tag;
private final String key;
private String groupKey;
@@ -44,13 +45,13 @@ public class StatusBarNotification implements Parcelable {
@UnsupportedAppUsage
private final int uid;
private final String opPkg;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int initialPid;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Notification notification;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final UserHandle user;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final long postTime;
private Context mContext; // used for inflation & icon expansion
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index f295b705e4e6..a011d677fc6a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -35,6 +35,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -197,7 +198,7 @@ public abstract class WallpaperService extends Service {
final Object mLock = new Object();
boolean mOffsetMessageEnqueued;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
float mPendingXOffset;
float mPendingYOffset;
float mPendingXOffsetStep;
diff --git a/core/java/android/text/method/HideReturnsTransformationMethod.java b/core/java/android/text/method/HideReturnsTransformationMethod.java
index e753754a38d4..440a4b187173 100644
--- a/core/java/android/text/method/HideReturnsTransformationMethod.java
+++ b/core/java/android/text/method/HideReturnsTransformationMethod.java
@@ -17,6 +17,7 @@
package android.text.method;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
/**
* This transformation method causes any carriage return characters (\r)
@@ -50,6 +51,6 @@ extends ReplacementTransformationMethod {
return sInstance;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static HideReturnsTransformationMethod sInstance;
}
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index 479fdf4cbb23..c96fc5de0845 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -18,6 +18,7 @@ package android.text.method;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
@@ -264,6 +265,6 @@ implements TransformationMethod, TextWatcher
@UnsupportedAppUsage
private static PasswordTransformationMethod sInstance;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static char DOT = '\u2022';
}
diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java
index 679698bbfb55..9b1dfbfc95e6 100644
--- a/core/java/android/text/style/BulletSpan.java
+++ b/core/java/android/text/style/BulletSpan.java
@@ -24,6 +24,7 @@ import android.annotation.Px;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.os.Build;
import android.os.Parcel;
import android.text.Layout;
import android.text.ParcelableSpan;
@@ -69,14 +70,14 @@ public class BulletSpan implements LeadingMarginSpan, ParcelableSpan {
private static final int STANDARD_COLOR = 0;
@Px
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mGapWidth;
@Px
private final int mBulletRadius;
@ColorInt
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mColor;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final boolean mWantColor;
/**
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index e87fcff3ee4b..af73a16e012a 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -17,6 +17,7 @@
package android.util;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -109,7 +110,7 @@ public class DebugUtils {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static void buildShortClassTag(Object cls, StringBuilder out) {
if (cls == null) {
out.append("null");
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 55245065c082..f31ddd9b0307 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -28,7 +28,7 @@ import android.hardware.camera2.utils.HashCodeHelpers;
* "integers from 1 to 100 inclusive."
* </p>
* <p>
- * All ranges are bounded, and the left side of the range is always {@code >=}
+ * All ranges are bounded, and the left side of the range is always {@code <=}
* the right side of the range.
* </p>
*
diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java
index c9fc3f2d1bcc..a85120f67f8d 100644
--- a/core/java/android/util/Slog.java
+++ b/core/java/android/util/Slog.java
@@ -17,6 +17,7 @@
package android.util;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
/**
* @hide
@@ -105,7 +106,7 @@ public final class Slog {
* will always be handled asynchronously. Primarily for use by coding running within
* the system process.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int wtfStack(String tag, String msg) {
return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true);
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 57d55bf31375..91bc3eb5f83a 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -19,6 +19,7 @@ package android.util;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.SystemClock;
import libcore.timezone.CountryTimeZones;
@@ -289,7 +290,7 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
synchronized (sFormatSync) {
int len = formatDurationLocked(duration, fieldLen);
@@ -306,7 +307,7 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static void formatDuration(long duration, PrintWriter pw) {
formatDuration(duration, pw, 0);
}
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index 9f7560c79166..54cfc00cb5b3 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -147,6 +147,9 @@ public final class AccessibilityIterators {
@Override
public void onConfigurationChanged(Configuration globalConfig) {
final Locale locale = globalConfig.getLocales().get(0);
+ if (locale == null) {
+ return;
+ }
if (!mLocale.equals(locale)) {
mLocale = locale;
onLocaleChanged(locale);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 97625869209d..d1115c7b4d1d 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -250,4 +250,10 @@ interface IWindowSession {
*/
void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
int height);
+
+ /**
+ * Called when the client has changed the local insets state, and now the server should reflect
+ * that new state.
+ */
+ void insetsModified(IWindow window, in InsetsState state);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 4ab1f266cc70..01af37e75cb9 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -19,7 +19,9 @@ package android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
+import android.os.RemoteException;
import android.util.ArraySet;
+import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetType;
@@ -36,7 +38,11 @@ import java.util.ArrayList;
*/
public class InsetsController implements WindowInsetsController {
+ private final String TAG = "InsetsControllerImpl";
+
private final InsetsState mState = new InsetsState();
+ private final InsetsState mTmpState = new InsetsState();
+
private final Rect mFrame = new Rect();
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
private final ViewRootImpl mViewRoot;
@@ -61,8 +67,12 @@ public class InsetsController implements WindowInsetsController {
return false;
}
mState.set(state);
+ mTmpState.set(state, true /* copySources */);
applyLocalVisibilityOverride();
mViewRoot.notifyInsetsChanged();
+ if (!mState.equals(mTmpState)) {
+ sendStateToWindowManager();
+ }
return true;
}
@@ -163,6 +173,27 @@ public class InsetsController implements WindowInsetsController {
@VisibleForTesting
public void notifyVisibilityChanged() {
mViewRoot.notifyInsetsChanged();
+ sendStateToWindowManager();
+ }
+
+ /**
+ * Sends the local visibility state back to window manager.
+ */
+ private void sendStateToWindowManager() {
+ InsetsState tmpState = new InsetsState();
+ for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
+ final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+ if (consumer.getControl() != null) {
+ tmpState.addSource(mState.getSource(consumer.getType()));
+ }
+ }
+
+ // TODO: Put this on a dispatcher thread.
+ try {
+ mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, tmpState);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call insetsModified", e);
+ }
}
void dump(String prefix, PrintWriter pw) {
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index f8148a906bb3..fbc72a0f978e 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -65,6 +65,10 @@ public class InsetsSource implements Parcelable {
return mFrame;
}
+ public boolean isVisible() {
+ return mVisible;
+ }
+
/**
* Calculates the insets this source will cause to a client window.
*
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index ec85c4c56cfc..145b09763676 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -35,7 +35,7 @@ public class InsetsSourceConsumer {
private final InsetsState mState;
private final InsetsController mController;
private @Nullable InsetsSourceControl mSourceControl;
- private boolean mHidden;
+ private boolean mVisible;
public InsetsSourceConsumer(@InternalInsetType int type, InsetsState state,
Supplier<Transaction> transactionSupplier, InsetsController controller) {
@@ -43,6 +43,7 @@ public class InsetsSourceConsumer {
mState = state;
mTransactionSupplier = transactionSupplier;
mController = controller;
+ mVisible = InsetsState.getDefaultVisibly(type);
}
public void setControl(@Nullable InsetsSourceControl control) {
@@ -51,8 +52,9 @@ public class InsetsSourceConsumer {
}
mSourceControl = control;
applyHiddenToControl();
- applyLocalVisibilityOverride();
- mController.notifyVisibilityChanged();
+ if (applyLocalVisibilityOverride()) {
+ mController.notifyVisibilityChanged();
+ }
}
@VisibleForTesting
@@ -66,28 +68,32 @@ public class InsetsSourceConsumer {
@VisibleForTesting
public void show() {
- setHidden(false);
+ setVisible(true);
}
@VisibleForTesting
public void hide() {
- setHidden(true);
+ setVisible(false);
}
- void applyLocalVisibilityOverride() {
+ boolean applyLocalVisibilityOverride() {
// If we don't have control, we are not able to change the visibility.
if (mSourceControl == null) {
- return;
+ return false;
+ }
+ if (mState.getSource(mType).isVisible() == mVisible) {
+ return false;
}
- mState.getSource(mType).setVisible(!mHidden);
+ mState.getSource(mType).setVisible(mVisible);
+ return true;
}
- private void setHidden(boolean hidden) {
- if (mHidden == hidden) {
+ private void setVisible(boolean visible) {
+ if (mVisible == visible) {
return;
}
- mHidden = hidden;
+ mVisible = visible;
applyHiddenToControl();
applyLocalVisibilityOverride();
mController.notifyVisibilityChanged();
@@ -100,10 +106,10 @@ public class InsetsSourceConsumer {
// TODO: Animation
final Transaction t = mTransactionSupplier.get();
- if (mHidden) {
- t.hide(mSourceControl.getLeash());
- } else {
+ if (mVisible) {
t.show(mSourceControl.getLeash());
+ } else {
+ t.hide(mSourceControl.getLeash());
}
t.apply();
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 63025dc16f17..885b3e94c593 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -32,6 +32,7 @@ import android.view.WindowInsets.Type.InsetType;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
/**
* Holder for state of system windows that cause window insets for all other windows in the system.
@@ -200,6 +201,18 @@ public class InsetsState implements Parcelable {
}
}
+ public void addSource(InsetsSource source) {
+ mSources.put(source.getType(), source);
+ }
+
+ public int getSourcesCount() {
+ return mSources.size();
+ }
+
+ public InsetsSource sourceAt(int index) {
+ return mSources.valueAt(index);
+ }
+
public static @InternalInsetType ArraySet<Integer> toInternalType(@InsetType int insetTypes) {
final ArraySet<Integer> result = new ArraySet<>();
if ((insetTypes & Type.TOP_BAR) != 0) {
@@ -216,6 +229,20 @@ public class InsetsState implements Parcelable {
return result;
}
+ public static boolean getDefaultVisibly(@InsetType int type) {
+ switch (type) {
+ case TYPE_TOP_BAR:
+ case TYPE_SIDE_BAR_1:
+ case TYPE_SIDE_BAR_2:
+ case TYPE_SIDE_BAR_3:
+ return true;
+ case TYPE_IME:
+ return false;
+ default:
+ return true;
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "InsetsState");
for (int i = mSources.size() - 1; i >= 0; i--) {
@@ -223,7 +250,7 @@ public class InsetsState implements Parcelable {
}
}
- static String typeToString(int type) {
+ public static String typeToString(int type) {
switch (type) {
case TYPE_TOP_BAR:
return "TYPE_TOP_BAR";
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index a4d3ce7e20bd..ffd4156b5bfd 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -784,24 +784,8 @@ public abstract class LayoutInflater {
ta.recycle();
}
- if (name.equals(TAG_1995)) {
- // Let's party like it's 1995!
- return new BlinkLayout(context, attrs);
- }
-
try {
- View view;
- if (mFactory2 != null) {
- view = mFactory2.onCreateView(parent, name, context, attrs);
- } else if (mFactory != null) {
- view = mFactory.onCreateView(name, context, attrs);
- } else {
- view = null;
- }
-
- if (view == null && mPrivateFactory != null) {
- view = mPrivateFactory.onCreateView(parent, name, context, attrs);
- }
+ View view = tryCreateView(parent, name, context, attrs);
if (view == null) {
final Object lastContext = mConstructorArgs[0];
@@ -836,6 +820,48 @@ public abstract class LayoutInflater {
}
/**
+ * Tries to create a view from a tag name using the supplied attribute set.
+ *
+ * This method gives the factory provided by {@link LayoutInflater#setFactory} and
+ * {@link LayoutInflater#setFactory2} a chance to create a view. However, it does not apply all
+ * of the general view creation logic, and thus may return {@code null} for some tags. This
+ * method is used by {@link LayoutInflater#inflate} in creating {@code View} objects.
+ *
+ * @hide for use by precompiled layouts.
+ *
+ * @param parent the parent view, used to inflate layout params
+ * @param name the name of the XML tag used to define the view
+ * @param context the inflation context for the view, typically the
+ * {@code parent} or base layout inflater context
+ * @param attrs the attribute set for the XML tag used to define the view
+ */
+ @UnsupportedAppUsage(trackingBug = 122360734)
+ @Nullable
+ public final View tryCreateView(@Nullable View parent, @NonNull String name,
+ @NonNull Context context,
+ @NonNull AttributeSet attrs) {
+ if (name.equals(TAG_1995)) {
+ // Let's party like it's 1995!
+ return new BlinkLayout(context, attrs);
+ }
+
+ View view;
+ if (mFactory2 != null) {
+ view = mFactory2.onCreateView(parent, name, context, attrs);
+ } else if (mFactory != null) {
+ view = mFactory.onCreateView(name, context, attrs);
+ } else {
+ view = null;
+ }
+
+ if (view == null && mPrivateFactory != null) {
+ view = mPrivateFactory.onCreateView(parent, name, context, attrs);
+ }
+
+ return view;
+ }
+
+ /**
* Recursive method used to inflate internal (non-root) children. This
* method calls through to {@link #rInflate} using the parent context as
* the inflation context.
@@ -921,127 +947,127 @@ public abstract class LayoutInflater {
AttributeSet attrs) throws XmlPullParserException, IOException {
int type;
- if (parent instanceof ViewGroup) {
- // Apply a theme wrapper, if requested. This is sort of a weird
- // edge case, since developers think the <include> overwrites
- // values in the AttributeSet of the included View. So, if the
- // included View has a theme attribute, we'll need to ignore it.
- final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
- final int themeResId = ta.getResourceId(0, 0);
- final boolean hasThemeOverride = themeResId != 0;
- if (hasThemeOverride) {
- context = new ContextThemeWrapper(context, themeResId);
- }
- ta.recycle();
-
- // If the layout is pointing to a theme attribute, we have to
- // massage the value to get a resource identifier out of it.
- int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
- if (layout == 0) {
- final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
- if (value == null || value.length() <= 0) {
- throw new InflateException("You must specify a layout in the"
- + " include tag: <include layout=\"@layout/layoutID\" />");
- }
+ if (!(parent instanceof ViewGroup)) {
+ throw new InflateException("<include /> can only be used inside of a ViewGroup");
+ }
- // Attempt to resolve the "?attr/name" string to an attribute
- // within the default (e.g. application) package.
- layout = context.getResources().getIdentifier(
- value.substring(1), "attr", context.getPackageName());
+ // Apply a theme wrapper, if requested. This is sort of a weird
+ // edge case, since developers think the <include> overwrites
+ // values in the AttributeSet of the included View. So, if the
+ // included View has a theme attribute, we'll need to ignore it.
+ final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+ final int themeResId = ta.getResourceId(0, 0);
+ final boolean hasThemeOverride = themeResId != 0;
+ if (hasThemeOverride) {
+ context = new ContextThemeWrapper(context, themeResId);
+ }
+ ta.recycle();
+ // If the layout is pointing to a theme attribute, we have to
+ // massage the value to get a resource identifier out of it.
+ int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+ if (value == null || value.length() <= 0) {
+ throw new InflateException("You must specify a layout in the"
+ + " include tag: <include layout=\"@layout/layoutID\" />");
}
- // The layout might be referencing a theme attribute.
- if (mTempValue == null) {
- mTempValue = new TypedValue();
- }
- if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
- layout = mTempValue.resourceId;
- }
+ // Attempt to resolve the "?attr/name" string to an attribute
+ // within the default (e.g. application) package.
+ layout = context.getResources().getIdentifier(
+ value.substring(1), "attr", context.getPackageName());
- if (layout == 0) {
- final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
- throw new InflateException("You must specify a valid layout "
- + "reference. The layout ID " + value + " is not valid.");
- } else {
- final XmlResourceParser childParser = context.getResources().getLayout(layout);
+ }
- try {
- final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+ // The layout might be referencing a theme attribute.
+ if (mTempValue == null) {
+ mTempValue = new TypedValue();
+ }
+ if (layout != 0 && context.getTheme().resolveAttribute(layout, mTempValue, true)) {
+ layout = mTempValue.resourceId;
+ }
- while ((type = childParser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty.
- }
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+ throw new InflateException("You must specify a valid layout "
+ + "reference. The layout ID " + value + " is not valid.");
+ }
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(childParser.getPositionDescription() +
- ": No start tag found!");
- }
+ final XmlResourceParser childParser = context.getResources().getLayout(layout);
- final String childName = childParser.getName();
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
- if (TAG_MERGE.equals(childName)) {
- // The <merge> tag doesn't support android:theme, so
- // nothing special to do here.
- rInflate(childParser, parent, context, childAttrs, false);
- } else {
- final View view = createViewFromTag(parent, childName,
- context, childAttrs, hasThemeOverride);
- final ViewGroup group = (ViewGroup) parent;
-
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.Include);
- final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
- final int visibility = a.getInt(R.styleable.Include_visibility, -1);
- a.recycle();
-
- // We try to load the layout params set in the <include /> tag.
- // If the parent can't generate layout params (ex. missing width
- // or height for the framework ViewGroups, though this is not
- // necessarily true of all ViewGroups) then we expect it to throw
- // a runtime exception.
- // We catch this exception and set localParams accordingly: true
- // means we successfully loaded layout params from the <include>
- // tag, false means we need to rely on the included layout params.
- ViewGroup.LayoutParams params = null;
- try {
- params = group.generateLayoutParams(attrs);
- } catch (RuntimeException e) {
- // Ignore, just fail over to child attrs.
- }
- if (params == null) {
- params = group.generateLayoutParams(childAttrs);
- }
- view.setLayoutParams(params);
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
- // Inflate all children.
- rInflateChildren(childParser, view, childAttrs, true);
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
- if (id != View.NO_ID) {
- view.setId(id);
- }
+ final String childName = childParser.getName();
- switch (visibility) {
- case 0:
- view.setVisibility(View.VISIBLE);
- break;
- case 1:
- view.setVisibility(View.INVISIBLE);
- break;
- case 2:
- view.setVisibility(View.GONE);
- break;
- }
+ if (TAG_MERGE.equals(childName)) {
+ // The <merge> tag doesn't support android:theme, so
+ // nothing special to do here.
+ rInflate(childParser, parent, context, childAttrs, false);
+ } else {
+ final View view = createViewFromTag(parent, childName,
+ context, childAttrs, hasThemeOverride);
+ final ViewGroup group = (ViewGroup) parent;
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Include);
+ final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+ a.recycle();
+
+ // We try to load the layout params set in the <include /> tag.
+ // If the parent can't generate layout params (ex. missing width
+ // or height for the framework ViewGroups, though this is not
+ // necessarily true of all ViewGroups) then we expect it to throw
+ // a runtime exception.
+ // We catch this exception and set localParams accordingly: true
+ // means we successfully loaded layout params from the <include>
+ // tag, false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ // Ignore, just fail over to child attrs.
+ }
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
- group.addView(view);
- }
- } finally {
- childParser.close();
+ // Inflate all children.
+ rInflateChildren(childParser, view, childAttrs, true);
+
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
+
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
}
+
+ group.addView(view);
}
- } else {
- throw new InflateException("<include /> can only be used inside of a ViewGroup");
+ } finally {
+ childParser.close();
}
LayoutInflater.consumeChildElements(parser);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a006e5de283e..1a708e8e30ec 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -165,7 +165,8 @@ public class SurfaceControl implements Parcelable {
private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject,
InputWindowHandle handle);
-
+ private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
+ IBinder toToken);
private final CloseGuard mCloseGuard = CloseGuard.get();
private final String mName;
@@ -1541,6 +1542,21 @@ public class SurfaceControl implements Parcelable {
return this;
}
+ /**
+ * Transfers touch focus from one window to another. It is possible for multiple windows to
+ * have touch focus if they support split touch dispatch
+ * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
+ * method only transfers touch focus of the specified window without affecting
+ * other windows that may also have touch focus at the same time.
+ * @param fromToken The token of a window that currently has touch focus.
+ * @param toToken The token of the window that should receive touch focus in
+ * place of the first.
+ */
+ public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
+ nativeTransferTouchFocus(mNativeObject, fromToken, toToken);
+ return this;
+ }
+
@UnsupportedAppUsage
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 797d1c5f47aa..a0af83d17abd 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -110,7 +110,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
final ReentrantLock mSurfaceLock = new ReentrantLock();
@UnsupportedAppUsage
final Surface mSurface = new Surface(); // Current surface in use
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
boolean mDrawingStopped = true;
// We use this to track if the application has produced a frame
// in to the Surface. Up until that point, we should be careful not to punch
@@ -129,7 +129,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
boolean mIsCreating = false;
private volatile boolean mRtHandlingPositionUpdates = false;
@@ -159,9 +159,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
boolean mViewVisibility = false;
boolean mWindowStopped = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mRequestedWidth = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mRequestedHeight = -1;
/* Set SurfaceView's format to 565 by default to maintain backward
* compatibility with applications assuming this format.
@@ -172,7 +172,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
@UnsupportedAppUsage
boolean mHaveFrame = false;
boolean mSurfaceCreated = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
long mLastLockTime = 0;
boolean mVisible = false;
@@ -182,7 +182,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
int mSurfaceHeight = -1;
@UnsupportedAppUsage
int mFormat = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
private Translator mTranslator;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 57635efff72e..6b07efc0b448 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4683,7 +4683,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* a long press could be performed before the tap is checked, in which case the tap's action
* should not be invoked.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mHasPerformedLongPress;
/**
@@ -14840,7 +14840,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param flags Constant indicating the value which should be set
* @param mask Constant indicating the bit range that should be changed
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
void setFlags(int flags, int mask) {
final boolean accessibilityEnabled =
AccessibilityManager.getInstance(mContext).isEnabled();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 741510e67130..8372032593b0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -143,7 +143,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
protected OnHierarchyChangeListener mOnHierarchyChangeListener;
// The view contained within this ViewGroup that has or contains focus.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private View mFocused;
// The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
// that is or contains a default-focus view.
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 58ab817c6faf..097f368ac2a8 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -38,6 +38,7 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.session.MediaController;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -282,7 +283,7 @@ public abstract class Window {
private WindowControllerCallback mWindowControllerCallback;
private OnRestrictedCaptionAreaChangedListener mOnRestrictedCaptionAreaChangedListener;
private Rect mRestrictedCaptionAreaRect;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private WindowManager mWindowManager;
@UnsupportedAppUsage
private IBinder mAppToken;
@@ -1296,7 +1297,7 @@ public abstract class Window {
public abstract void alwaysReadCloseOnTouchAttr();
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
final boolean isOutside =
event.getAction() == MotionEvent.ACTION_DOWN && isOutOfBounds(context, event)
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 9f666a40bef3..46e6882b8643 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -34,6 +34,7 @@ import dalvik.system.CloseGuard;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Session used to notify a system-provided Content Capture service about events associated with
@@ -41,6 +42,8 @@ import java.util.UUID;
*/
public abstract class ContentCaptureSession implements AutoCloseable {
+ private static final String TAG = ContentCaptureSession.class.getSimpleName();
+
/**
* Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
*
@@ -85,11 +88,14 @@ public abstract class ContentCaptureSession implements AutoCloseable {
private static final int INITIAL_CHILDREN_CAPACITY = 5;
- /** @hide */
- protected final String mTag = getClass().getSimpleName();
-
private final CloseGuard mCloseGuard = CloseGuard.get();
+ /**
+ * Guard use to ignore events after it's destroyed.
+ */
+ @NonNull
+ private final AtomicBoolean mDestroyed = new AtomicBoolean();
+
/** @hide */
@Nullable
protected final String mId = UUID.randomUUID().toString();
@@ -134,7 +140,7 @@ public abstract class ContentCaptureSession implements AutoCloseable {
@NonNull ContentCaptureContext context) {
final ContentCaptureSession child = newChild(context);
if (DEBUG) {
- Log.d(mTag, "createContentCaptureSession(" + context + ": parent=" + mId + ", child= "
+ Log.d(TAG, "createContentCaptureSession(" + context + ": parent=" + mId + ", child="
+ child.mId);
}
if (mChildren == null) {
@@ -157,29 +163,29 @@ public abstract class ContentCaptureSession implements AutoCloseable {
* <p>Once destroyed, any new notification will be dropped.
*/
public final void destroy() {
- //TODO(b/111276913): mark it as destroyed so other methods are ignored (and test on CTS)
-
- //TODO(b/111276913): probably shouldn't check for it
- if (!isContentCaptureEnabled()) return;
+ if (!mDestroyed.compareAndSet(false, true)) {
+ Log.e(TAG, "destroy(): already destroyed");
+ return;
+ }
mCloseGuard.close();
//TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
// id) and send it to the cache of batched commands
if (VERBOSE) {
- Log.v(mTag, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
+ Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
}
// Finish children first
if (mChildren != null) {
final int numberChildren = mChildren.size();
- if (VERBOSE) Log.v(mTag, "Destroying " + numberChildren + " children first");
+ if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first");
for (int i = 0; i < numberChildren; i++) {
final ContentCaptureSession child = mChildren.get(i);
try {
child.destroy();
} catch (Exception e) {
- Log.w(mTag, "exception destroying child session #" + i + ": " + e);
+ Log.w(TAG, "exception destroying child session #" + i + ": " + e);
}
}
}
@@ -298,14 +304,18 @@ public abstract class ContentCaptureSession implements AutoCloseable {
return new ViewNode.ViewStructureImpl(parentId, virtualId);
}
- abstract boolean isContentCaptureEnabled();
+ boolean isContentCaptureEnabled() {
+ return !mDestroyed.get();
+ }
@CallSuper
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix); pw.print("id: "); pw.println(mId);
+ pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed.get());
if (mChildren != null && !mChildren.isEmpty()) {
final String prefix2 = prefix + " ";
final int numberChildren = mChildren.size();
- pw.print(prefix); pw.print("number children: "); pw.print(numberChildren);
+ pw.print(prefix); pw.print("number children: "); pw.println(numberChildren);
for (int i = 0; i < numberChildren; i++) {
final ContentCaptureSession child = mChildren.get(i);
pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw);
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index ea6f2fe16ef6..baf4a35f179e 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -63,6 +63,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public final class MainContentCaptureSession extends ContentCaptureSession {
+ private static final String TAG = MainContentCaptureSession.class.getSimpleName();
+
/**
* Handler message used to flush the buffer.
*/
@@ -128,9 +130,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
// Used just for debugging purposes (on dump)
private long mNextFlush;
- // Lazily created on demand.
- private ContentCaptureSessionId mContentCaptureSessionId;
-
/** @hide */
protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
@Nullable IContentCaptureManager systemServerInterface,
@@ -157,7 +156,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (!isContentCaptureEnabled()) return;
if (VERBOSE) {
- Log.v(mTag, "start(): token=" + applicationToken + ", comp="
+ Log.v(TAG, "start(): token=" + applicationToken + ", comp="
+ ComponentName.flattenToShortString(activityComponent));
}
@@ -179,7 +178,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) {
if (mState != STATE_UNKNOWN) {
// TODO(b/111276913): revisit this scenario
- Log.w(mTag, "ignoring handleStartSession(" + token + ") while on state "
+ Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state "
+ getStateAsString(mState));
return;
}
@@ -188,7 +187,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
mComponentName = componentName;
if (VERBOSE) {
- Log.v(mTag, "handleStartSession(): token=" + token + ", act="
+ Log.v(TAG, "handleStartSession(): token=" + token + ", act="
+ getActivityDebugName() + ", id=" + mId);
}
final int flags = 0; // TODO(b/111276913): get proper flags
@@ -202,7 +201,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (resultData != null) {
binder = resultData.getBinder(EXTRA_BINDER);
if (binder == null) {
- Log.wtf(mTag, "No " + EXTRA_BINDER + " extra result");
+ Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
handleResetState();
return;
}
@@ -211,7 +210,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
});
} catch (RemoteException e) {
- Log.w(mTag, "Error starting session for " + componentName.flattenToShortString() + ": "
+ Log.w(TAG, "Error starting session for " + componentName.flattenToShortString() + ": "
+ e);
}
}
@@ -219,7 +218,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
/**
* Callback from {@code system_server} after call to
* {@link IContentCaptureManager#startSession(int, IBinder, ComponentName, String,
- * ContentCaptureContext, int, IResultReceiver)}.
+ * int, IResultReceiver)}.
*
* @param resultCode session state
* @param binder handle to {@code IContentCaptureDirectManager}
@@ -229,13 +228,13 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (binder != null) {
mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
mDirectServiceVulture = () -> {
- Log.w(mTag, "Destroying session " + mId + " because service died");
+ Log.w(TAG, "Destroying session " + mId + " because service died");
destroy();
};
try {
binder.linkToDeath(mDirectServiceVulture, 0);
} catch (RemoteException e) {
- Log.w(mTag, "Failed to link to death on " + binder + ": " + e);
+ Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
}
}
if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
@@ -245,7 +244,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
mDisabled.set(false);
}
if (VERBOSE) {
- Log.v(mTag, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+ Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+ ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
+ ", binder=" + binder);
}
@@ -254,18 +253,31 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
if (mEvents == null) {
if (VERBOSE) {
- Log.v(mTag, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
+ Log.v(TAG, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
}
mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
}
- mEvents.add(event);
+
+ if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+ final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
+
+ // TODO(b/121045053): check if flags match
+ if (lastEvent.getType() == TYPE_VIEW_TEXT_CHANGED
+ && lastEvent.getId().equals(event.getId())) {
+ if (VERBOSE) {
+ Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text = "
+ + event.getText());
+ }
+ lastEvent.setText(event.getText());
+ } else {
+ mEvents.add(event);
+ }
+ } else {
+ mEvents.add(event);
+ }
final int numberEvents = mEvents.size();
- // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are
- // buffered (either total or per autofillid). For
- // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer
- // "a" and "b" then send "abc".
final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
if (bufferEvent && !forceFlush) {
@@ -280,7 +292,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
// not complete instead. Similarly, the manager service should return right away
// when the user does not have a service set
if (VERBOSE) {
- Log.v(mTag, "Closing session for " + getActivityDebugName()
+ Log.v(TAG, "Closing session for " + getActivityDebugName()
+ " after " + numberEvents + " delayed events and state "
+ getStateAsString(mState));
}
@@ -300,7 +312,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
if (VERBOSE) {
- Log.v(mTag, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+ Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
}
mHandler.sendMessageDelayed(
obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
@@ -309,7 +321,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private void handleFlushIfNeeded() {
if (mEvents.isEmpty()) {
- if (VERBOSE) Log.v(mTag, "Nothing to flush");
+ if (VERBOSE) Log.v(TAG, "Nothing to flush");
return;
}
handleForceFlush();
@@ -319,7 +331,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
if (mEvents == null) return;
if (mDirectServiceInterface == null) {
- if (DEBUG) Log.d(mTag, "handleForceFlush(): hold your horses, client not ready yet!");
+ if (DEBUG) Log.d(TAG, "handleForceFlush(): hold your horses, client not ready yet!");
if (!mHandler.hasMessages(MSG_FLUSH)) {
handleScheduleFlush(/* checkExisting= */ false);
}
@@ -329,14 +341,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
final int numberEvents = mEvents.size();
try {
if (DEBUG) {
- Log.d(mTag, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
+ Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
}
mHandler.removeMessages(MSG_FLUSH);
final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
mDirectServiceInterface.sendEvents(events);
} catch (RemoteException e) {
- Log.w(mTag, "Error sending " + numberEvents + " for " + getActivityDebugName()
+ Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName()
+ ": " + e);
}
}
@@ -357,7 +369,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
private void handleDestroySession() {
if (DEBUG) {
- Log.d(mTag, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+ (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
+ getActivityDebugName());
}
@@ -365,7 +377,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
try {
mSystemServerInterface.finishSession(mContext.getUserId(), mId);
} catch (RemoteException e) {
- Log.e(mTag, "Error destroying system-service session " + mId + " for "
+ Log.e(TAG, "Error destroying system-service session " + mId + " for "
+ getActivityDebugName() + ": " + e);
}
}
@@ -382,8 +394,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
// TODO(b/121033016): must reset children (which currently is owned by superclass)
-
- mContentCaptureSessionId = null;
mApplicationToken = null;
mComponentName = null;
mEvents = null;
@@ -412,7 +422,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
@Override
boolean isContentCaptureEnabled() {
- return mSystemServerInterface != null && !mDisabled.get();
+ return super.isContentCaptureEnabled() && mSystemServerInterface != null
+ && !mDisabled.get();
}
// TODO(b/121033016): refactor "notifyXXXX" methods below to a common "Buffer" object that is
@@ -468,9 +479,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
- if (mContentCaptureSessionId != null) {
- pw.print(prefix); pw.print("public id: "); pw.println(mContentCaptureSessionId);
- }
pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
pw.print(getStateAsString(mState)); pw.println(")");
if (mApplicationToken != null) {
diff --git a/core/java/android/webkit/ConsoleMessage.java b/core/java/android/webkit/ConsoleMessage.java
index 6051956531e4..e54849772f9a 100644
--- a/core/java/android/webkit/ConsoleMessage.java
+++ b/core/java/android/webkit/ConsoleMessage.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
/**
* Public class representing a JavaScript console message from WebCore. This could be a issued
@@ -36,13 +37,13 @@ public class ConsoleMessage {
DEBUG
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private MessageLevel mLevel;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mMessage;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mSourceId;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mLineNumber;
public ConsoleMessage(String message, String sourceId, int lineNumber, MessageLevel msgLevel) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 414cb8f30fc7..bad2dbfebdc5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -850,7 +850,7 @@ public class WebView extends AbsoluteLayout
/**
* Asynchronously evaluates JavaScript in the context of the currently displayed page.
- * If non-null, |resultCallback| will be invoked with any result returned from that
+ * If non-null, {@code resultCallback} will be invoked with any result returned from that
* execution. This method must be called on the UI thread and the callback will
* be made on the UI thread.
* <p>
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 6ab7f66aedd3..ef69b6333cce 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -138,6 +138,20 @@ public final class WebViewDelegate {
}
/**
+ * Call webview draw functor. See API in draw_fn.h.
+ * @param canvas a hardware accelerated canvas (see {@link Canvas#isHardwareAccelerated()}).
+ * @param functor created by AwDrawFn_CreateFunctor in draw_fn.h.
+ */
+ public void drawWebViewFunctor(@NonNull Canvas canvas, int functor) {
+ if (!(canvas instanceof RecordingCanvas)) {
+ // Canvas#isHardwareAccelerated() is only true for subclasses of RecordingCanvas.
+ throw new IllegalArgumentException(canvas.getClass().getName()
+ + " is not a RecordingCanvas canvas");
+ }
+ ((RecordingCanvas) canvas).drawWebViewFunctor(functor);
+ }
+
+ /**
* Detaches the draw GL functor.
*
* @param nativeDrawGLFunctor the pointer to the native functor that implements
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 49e11b8baf51..9f7aa6a2852a 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -159,6 +159,7 @@ public class WebViewZygote {
0, // runtimeFlags
"webview_zygote", // seInfo
sPackage.applicationInfo.primaryCpuAbi, // abi
+ TextUtils.join(",", Build.SUPPORTED_ABIS),
null); // instructionSet
// All the work below is usually done by LoadedApk, but the zygote can't talk to
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 07096e815d15..99895bd65398 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -29,6 +29,7 @@ import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -316,7 +317,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
/**
* The drawable used to draw the selector
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Drawable mSelector;
/**
@@ -677,7 +678,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* ID of the active pointer. This is used to retain consistency during
* drags/flings if multiple pointers are used.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mActivePointerId = INVALID_POINTER;
/**
@@ -6571,7 +6572,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
@ViewDebug.IntToString(from = ITEM_VIEW_TYPE_IGNORE, to = "ITEM_VIEW_TYPE_IGNORE"),
@ViewDebug.IntToString(from = ITEM_VIEW_TYPE_HEADER_OR_FOOTER, to = "ITEM_VIEW_TYPE_HEADER_OR_FOOTER")
})
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int viewType;
/**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index ea1bfc2854c2..d6a0ae48cc13 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -22,6 +22,7 @@ import android.annotation.Widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
@@ -105,7 +106,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
/**
* Helper for detecting touch gestures.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private GestureDetector mGestureDetector;
/**
@@ -149,7 +150,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
/**
* The currently selected item's child.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private View mSelectedChild;
/**
@@ -480,7 +481,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
/**
* @return The center of this Gallery.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int getCenterOfGallery() {
return (getWidth() - mPaddingLeft - mPaddingRight) / 2 + mPaddingLeft;
}
@@ -488,7 +489,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
/**
* @return The center of the given view.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static int getCenterOfView(View view) {
return view.getLeft() + view.getWidth() / 2;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index ee04bcfddb27..9b497866486d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -28,6 +28,7 @@ import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.Trace;
import android.util.AttributeSet;
@@ -189,7 +190,7 @@ public class ListView extends AbsListView {
@UnsupportedAppUsage
Drawable mDivider;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
int mDividerHeight;
Drawable mOverScrollHeader;
@@ -1390,7 +1391,7 @@ public class ListView extends AbsListView {
* startPosition is 0).
* @return The height of this ListView with the given children.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
int maxHeight, int disallowPartialChildPosition) {
final ListAdapter adapter = mAdapter;
@@ -1533,7 +1534,7 @@ public class ListView extends AbsListView {
*
* @param childCount Number of children
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void correctTooHigh(int childCount) {
// First see if the last item is visible. If it is not, it is OK for the
// top of the list to be pushed up.
@@ -1583,7 +1584,7 @@ public class ListView extends AbsListView {
*
* @param childCount Number of children
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void correctTooLow(int childCount) {
// First see if the first item is visible. If it is not, it is OK for the
// bottom of the list to be pushed down.
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 82d77c528564..65925b446bbe 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.media.AudioManager;
+import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -87,9 +88,9 @@ public class MediaController extends FrameLayout {
private WindowManager.LayoutParams mDecorLayoutParams;
@UnsupportedAppUsage
private ProgressBar mProgress;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private TextView mEndTime;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private TextView mCurrentTime;
@UnsupportedAppUsage
private boolean mShowing;
@@ -107,9 +108,9 @@ public class MediaController extends FrameLayout {
private ImageButton mFfwdButton;
@UnsupportedAppUsage
private ImageButton mRewButton;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private ImageButton mNextButton;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private ImageButton mPrevButton;
private CharSequence mPlayDescription;
private CharSequence mPauseDescription;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 18838090f58b..ed6f0d6bcba3 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -206,9 +206,9 @@ public class PopupWindow {
private float mElevation;
private Drawable mBackground;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Drawable mAboveAnchorBackgroundDrawable;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Drawable mBelowAnchorBackgroundDrawable;
private Transition mEnterTransition;
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index a27354dc2bac..15e1ffa7bc31 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Build;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -59,7 +60,7 @@ public class SimpleAdapter extends BaseAdapter implements Filterable, ThemedSpin
private String[] mFrom;
private ViewBinder mViewBinder;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private List<? extends Map<String, ?>> mData;
private int mResource;
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index b670e6c83f9d..77fe5d1a9302 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -20,6 +20,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Build;
import android.view.View;
/**
@@ -52,7 +53,7 @@ public class SimpleCursorAdapter extends ResourceCursorAdapter {
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected int[] mFrom;
/**
* A list of View ids representing the views to which the data must be bound.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b5cdedc4ea80..0ea8579fafe6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -429,7 +429,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@ViewDebug.ExportedProperty(category = "text")
@UnsupportedAppUsage
private int mCurTextColor;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCurHintTextColor;
private boolean mFreezesText;
@@ -10013,7 +10013,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& mSavedMarqueeModeLayout.getLineWidth(0) > width));
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void startMarquee() {
// Do not ellipsize EditText
if (getKeyListener() != null) return;
@@ -10056,7 +10056,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void startStopMarquee(boolean start) {
if (mEllipsize == TextUtils.TruncateAt.MARQUEE) {
if (start) {
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 8b45d997627a..40b0f13c596b 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -113,7 +113,7 @@ public class VideoView extends SurfaceView
private int mTargetState = STATE_IDLE;
// All the stuff we need for playing and showing a video
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private SurfaceHolder mSurfaceHolder = null;
@UnsupportedAppUsage
private MediaPlayer mMediaPlayer = null;
@@ -565,7 +565,7 @@ public class VideoView extends SurfaceView
}
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index e83e79b2029e..925a5894db06 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -357,15 +357,16 @@ public class AccessibilityShortcutController {
}
private boolean performTtsPrompt(AlertDialog alertDialog) {
+ final String serviceName = getShortcutFeatureDescription(false /* no summary */);
final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
- if (serviceInfo == null) {
+ if (TextUtils.isEmpty(serviceName) || serviceInfo == null) {
return false;
}
if ((serviceInfo.flags & AccessibilityServiceInfo
.FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK) == 0) {
return false;
}
- final TtsPrompt tts = new TtsPrompt();
+ final TtsPrompt tts = new TtsPrompt(serviceName);
alertDialog.setOnDismissListener(dialog -> tts.dismiss());
return true;
}
@@ -378,8 +379,9 @@ public class AccessibilityShortcutController {
private boolean mDismiss;
private TextToSpeech mTts;
- TtsPrompt() {
- mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback);
+ TtsPrompt(String serviceName) {
+ mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback,
+ serviceName);
mTts = mFrameworkObjectProvider.getTextToSpeech(mContext, this);
}
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 78d366cd2436..2995a8f43268 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -16,14 +16,14 @@
package com.android.internal.hardware;
-import com.android.internal.R;
-
import android.content.Context;
import android.os.Build;
import android.os.SystemProperties;
import android.provider.Settings;
import android.text.TextUtils;
+import com.android.internal.R;
+
public class AmbientDisplayConfiguration {
private final Context mContext;
@@ -37,7 +37,8 @@ public class AmbientDisplayConfiguration {
public boolean enabled(int user) {
return pulseOnNotificationEnabled(user)
|| pulseOnLongPressEnabled(user)
- || alwaysOnEnabled(user);
+ || alwaysOnEnabled(user)
+ || wakeLockScreenGestureEnabled(user);
}
public boolean pulseOnNotificationEnabled(int user) {
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index bc4b5fe3ff17..ec02432223de 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -17,6 +17,7 @@
package com.android.internal.net;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -52,7 +53,7 @@ public class VpnProfile implements Cloneable, Parcelable {
public String name = ""; // 0
@UnsupportedAppUsage
public int type = TYPE_PPTP; // 1
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String server = ""; // 2
@UnsupportedAppUsage
public String username = ""; // 3
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
new file mode 100644
index 000000000000..afe6dade62ac
--- /dev/null
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
+import android.net.LocalSocket;
+import android.util.Log;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Startup class for an Application zygote process.
+ *
+ * See {@link ZygoteInit} for generic zygote startup documentation.
+ *
+ * @hide
+ */
+class AppZygoteInit {
+ public static final String TAG = "AppZygoteInit";
+
+ private static ZygoteServer sServer;
+
+ private static class AppZygoteServer extends ZygoteServer {
+ @Override
+ protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
+ throws IOException {
+ return new AppZygoteConnection(socket, abiList);
+ }
+ }
+
+ private static class AppZygoteConnection extends ZygoteConnection {
+ AppZygoteConnection(LocalSocket socket, String abiList) throws IOException {
+ super(socket, abiList);
+ }
+
+ @Override
+ protected void preload() {
+ // Nothing to preload by default.
+ }
+
+ @Override
+ protected boolean isPreloadComplete() {
+ // App zygotes don't preload any classes or resources or defaults, all of their
+ // preloading is package specific.
+ return true;
+ }
+
+ @Override
+ protected boolean canPreloadApp() {
+ return true;
+ }
+
+ @Override
+ protected void handlePreloadApp(ApplicationInfo appInfo) {
+ Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
+ LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
+ ClassLoader loader = loadedApk.getClassLoader();
+ Class<?> cl;
+ Method m;
+ try {
+ cl = Class.forName(appInfo.packageName + ".ZygotePreload", true, loader);
+ m = cl.getMethod("doPreload");
+ m.setAccessible(true);
+ m.invoke(null);
+ } catch (ClassNotFoundException e) {
+ // Don't treat this as an error since an app may not want to do any preloads
+ Log.w(TAG, "No ZygotePreload class found for " + appInfo.packageName);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ Log.e(TAG, "AppZygote application preload failed for "
+ + appInfo.packageName, e);
+ }
+ try {
+ DataOutputStream socketOut = getSocketOutputStream();
+ socketOut.writeInt(loader != null ? 1 : 0);
+ } catch (IOException e) {
+ throw new IllegalStateException("Error writing to command socket", e);
+ }
+
+ Log.i(TAG, "Application preload done");
+ }
+ }
+
+ public static void main(String[] argv) {
+ AppZygoteServer server = new AppZygoteServer();
+ ChildZygoteInit.runZygoteServer(server, argv);
+ }
+}
diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java
index e177fe303253..a72a2f5e1be3 100644
--- a/core/java/com/android/internal/os/AtomicFile.java
+++ b/core/java/com/android/internal/os/AtomicFile.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.FileUtils;
import android.util.Log;
@@ -51,7 +52,7 @@ public final class AtomicFile {
mBackupName = new File(baseName.getPath() + ".bak");
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public File getBaseFile() {
return mBaseName;
}
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
new file mode 100644
index 000000000000..f90cd0224596
--- /dev/null
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+/**
+ * ChildZygoteInit is shared by both the Application and WebView zygote to initialize
+ * and run a (child) Zygote server.
+ *
+ * @hide
+ */
+public class ChildZygoteInit {
+ private static final String TAG = "ChildZygoteInit";
+
+ static String parseSocketNameFromArgs(String[] argv) {
+ for (String arg : argv) {
+ if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+ return arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
+ }
+ }
+
+ return null;
+ }
+
+ static String parseAbiListFromArgs(String[] argv) {
+ for (String arg : argv) {
+ if (arg.startsWith(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG)) {
+ return arg.substring(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG.length());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Starts a ZygoteServer and listens for requests
+ *
+ * @param server An instance of a ZygoteServer to listen on
+ * @param args Passed in arguments for this ZygoteServer
+ */
+ static void runZygoteServer(ZygoteServer server, String[] args) {
+ String socketName = parseSocketNameFromArgs(args);
+ if (socketName == null) {
+ throw new NullPointerException("No socketName specified");
+ }
+
+ String abiList = parseAbiListFromArgs(args);
+ if (abiList == null) {
+ throw new NullPointerException("No abiList specified");
+ }
+
+ try {
+ Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ } catch (ErrnoException ex) {
+ throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
+ }
+
+ final Runnable caller;
+ try {
+ server.registerServerSocketAtAbstractName(socketName);
+
+ // Add the abstract socket to the FD whitelist so that the native zygote code
+ // can properly detach it after forking.
+ Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
+
+ // The select loop returns early in the child process after a fork and
+ // loops forever in the zygote.
+ caller = server.runSelectLoop(abiList);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Fatal exception:", e);
+ throw e;
+ } finally {
+ server.closeServerSocket();
+ }
+
+ // We're in the child process and have exited the select loop. Proceed to execute the
+ // command.
+ if (caller != null) {
+ caller.run();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index dc660a452c3b..a319d83b077d 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -30,6 +30,14 @@ public class RoSystemProperties {
public static final String CONTROL_PRIVAPP_PERMISSIONS =
SystemProperties.get("ro.control_privapp_permissions");
+ /**
+ * Property to indicate if a CEC audio device should forward volume keys when system audio
+ * mode is off.
+ */
+ public static final boolean CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF =
+ SystemProperties.getBoolean(
+ "ro.hdmi.cec_audio_device_forward_volume_keys_system_audio_mode_off", false);
+
// ------ ro.config.* -------- //
public static final boolean CONFIG_AVOID_GFX_ACCEL =
SystemProperties.getBoolean("ro.config.avoid_gfx_accel", false);
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 9f2434e97d7a..0b329d70f7af 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -18,11 +18,7 @@ package com.android.internal.os;
import android.app.ApplicationLoaders;
import android.net.LocalSocket;
-import android.net.LocalServerSocket;
import android.os.Build;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewFactory;
@@ -44,8 +40,6 @@ import java.lang.reflect.Method;
class WebViewZygoteInit {
public static final String TAG = "WebViewZygoteInit";
- private static ZygoteServer sServer;
-
private static class WebViewZygoteServer extends ZygoteServer {
@Override
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
@@ -127,48 +121,7 @@ class WebViewZygoteInit {
public static void main(String argv[]) {
Log.i(TAG, "Starting WebViewZygoteInit");
-
- String socketName = null;
- for (String arg : argv) {
- Log.i(TAG, arg);
- if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
- socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
- }
- }
- if (socketName == null) {
- throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
- }
-
- try {
- Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
- } catch (ErrnoException ex) {
- throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
- }
-
- sServer = new WebViewZygoteServer();
-
- final Runnable caller;
- try {
- sServer.registerServerSocketAtAbstractName(socketName);
-
- // Add the abstract socket to the FD whitelist so that the native zygote code
- // can properly detach it after forking.
- Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
-
- // The select loop returns early in the child process after a fork and
- // loops forever in the zygote.
- caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
- } catch (RuntimeException e) {
- Log.e(TAG, "Fatal exception:", e);
- throw e;
- } finally {
- sServer.closeServerSocket();
- }
-
- // We're in the child process and have exited the select loop. Proceed to execute the
- // command.
- if (caller != null) {
- caller.run();
- }
+ WebViewZygoteServer server = new WebViewZygoteServer();
+ ChildZygoteInit.runZygoteServer(server, argv);
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 65b9fad97d89..d720c689f5de 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -98,6 +98,12 @@ public final class Zygote {
*/
public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
+ /**
+ * An extraArg passed when a zygote process is forking a child-zygote, specifying the
+ * requested ABI for the child Zygote.
+ */
+ public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list=";
+
private Zygote() {}
/** Called for some security initialization before any fork. */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f182c4d447df..5990d72d89b4 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -27,9 +27,11 @@ import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEO
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
+import android.content.pm.ApplicationInfo;
import android.net.Credentials;
import android.net.LocalSocket;
import android.os.FactoryTest;
+import android.os.Parcel;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
@@ -52,6 +54,7 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Base64;
/**
* A connection that can make spawn requests.
@@ -168,6 +171,21 @@ class ZygoteConnection {
return null;
}
+ if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
+ byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
+ Parcel appInfoParcel = Parcel.obtain();
+ appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
+ appInfoParcel.setDataPosition(0);
+ ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
+ appInfoParcel.recycle();
+ if (appInfo != null) {
+ handlePreloadApp(appInfo);
+ } else {
+ throw new IllegalArgumentException("Failed to deserialize --preload-app");
+ }
+ return null;
+ }
+
if (parsedArgs.apiBlacklistExemptions != null) {
handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
return null;
@@ -341,7 +359,15 @@ class ZygoteConnection {
protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
String cacheKey) {
- throw new RuntimeException("Zyogte does not support package preloading");
+ throw new RuntimeException("Zygote does not support package preloading");
+ }
+
+ protected boolean canPreloadApp() {
+ return false;
+ }
+
+ protected void handlePreloadApp(ApplicationInfo aInfo) {
+ throw new RuntimeException("Zygote does not support app preloading");
}
/**
@@ -467,6 +493,12 @@ class ZygoteConnection {
String preloadPackage;
/**
+ * A Base64 string representing a serialize ApplicationInfo Parcel,
+ when using --preload-app.
+ */
+ String mPreloadApp;
+
+ /**
* The native library path of the package to preload, when using --preload-package.
*/
String preloadPackageLibs;
@@ -666,6 +698,8 @@ class ZygoteConnection {
instructionSet = arg.substring(arg.indexOf('=') + 1);
} else if (arg.startsWith("--app-data-dir=")) {
appDataDir = arg.substring(arg.indexOf('=') + 1);
+ } else if (arg.equals("--preload-app")) {
+ mPreloadApp = args[++curArg];
} else if (arg.equals("--preload-package")) {
preloadPackage = args[++curArg];
preloadPackageLibs = args[++curArg];
@@ -714,6 +748,11 @@ class ZygoteConnection {
throw new IllegalArgumentException(
"Unexpected arguments after --preload-package.");
}
+ } else if (mPreloadApp != null) {
+ if (args.length - curArg > 0) {
+ throw new IllegalArgumentException(
+ "Unexpected arguments after --preload-app.");
+ }
} else if (expectRuntimeArgs) {
if (!seenRuntimeArgs) {
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 69297b5582a5..b0888f2c8df9 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -21,6 +21,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -162,7 +163,7 @@ public class AsyncChannel {
sCmdToString[CMD_CHANNEL_DISCONNECT - BASE] = "CMD_CHANNEL_DISCONNECT";
sCmdToString[CMD_CHANNEL_DISCONNECTED - BASE] = "CMD_CHANNEL_DISCONNECTED";
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected static String cmdToString(int cmd) {
cmd -= BASE;
if ((cmd >= 0) && (cmd < sCmdToString.length)) {
@@ -591,7 +592,7 @@ public class AsyncChannel {
* @param srcMsg
* @param what
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void replyToMessage(Message srcMsg, int what) {
Message msg = Message.obtain();
msg.what = what;
diff --git a/core/java/com/android/internal/util/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
index 258db2a1fc48..065cc5b2416b 100644
--- a/core/java/com/android/internal/util/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import java.io.File;
import java.io.IOException;
@@ -47,7 +48,7 @@ public class JournaledFile {
* it to the real one. If there is both a real file and a temp one, assumes that the
* temp one isn't fully written and deletes it.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public File chooseForRead() {
File result;
if (mReal.exists()) {
@@ -72,7 +73,7 @@ public class JournaledFile {
* <p>
* Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public File chooseForWrite() {
if (mWriting) {
throw new IllegalStateException("uncommitted write already in progress");
@@ -100,7 +101,7 @@ public class JournaledFile {
/**
* Commit changes.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void commit() {
if (!mWriting) {
throw new IllegalStateException("no file to commit");
@@ -112,7 +113,7 @@ public class JournaledFile {
/**
* Roll back changes.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void rollback() {
if (!mWriting) {
throw new IllegalStateException("no file to roll back");
diff --git a/core/jni/android/graphics/text/LineBreaker.cpp b/core/jni/android/graphics/text/LineBreaker.cpp
index e1f2f2b8e069..c23f1e956cd4 100644
--- a/core/jni/android/graphics/text/LineBreaker.cpp
+++ b/core/jni/android/graphics/text/LineBreaker.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "LineBreaker"
-#include "unicode/locid.h"
-#include "unicode/brkiter.h"
#include "utils/misc.h"
#include "utils/Log.h"
#include <nativehelper/ScopedStringChars.h>
diff --git a/core/jni/android/graphics/text/MeasuredText.cpp b/core/jni/android/graphics/text/MeasuredText.cpp
index d7d96fbf3956..68ba38b93915 100644
--- a/core/jni/android/graphics/text/MeasuredText.cpp
+++ b/core/jni/android/graphics/text/MeasuredText.cpp
@@ -17,8 +17,6 @@
#define LOG_TAG "MeasuredText"
#include "GraphicsJNI.h"
-#include "unicode/locid.h"
-#include "unicode/brkiter.h"
#include "utils/misc.h"
#include "utils/Log.h"
#include <nativehelper/ScopedStringChars.h>
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 29d8f30543e6..80560f826235 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1906,6 +1906,53 @@ exit:
return jStatus;
}
+static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
+ jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) {
+ if (deviceTypes == nullptr || deviceAddresses == nullptr) {
+ return (jint) AUDIO_JAVA_BAD_VALUE;
+ }
+ jsize nb = env->GetArrayLength(deviceTypes);
+ if (nb == 0 || nb != env->GetArrayLength(deviceAddresses)) {
+ return (jint) AUDIO_JAVA_BAD_VALUE;
+ }
+ // retrieve all device types
+ std::vector<audio_devices_t> deviceTypesVector;
+ jint* typesPtr = nullptr;
+ typesPtr = env->GetIntArrayElements(deviceTypes, 0);
+ if (typesPtr == nullptr) {
+ return (jint) AUDIO_JAVA_BAD_VALUE;
+ }
+ for (jint i = 0; i < nb; i++) {
+ deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
+ }
+ env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
+
+ // check each address is a string and add device type/address to list for device affinity
+ Vector<AudioDeviceTypeAddr> deviceVector;
+ jclass stringClass = FindClassOrDie(env, "java/lang/String");
+ for (jint i = 0; i < nb; i++) {
+ jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
+ if (!env->IsInstanceOf(addrJobj, stringClass)) {
+ return (jint) AUDIO_JAVA_BAD_VALUE;
+ }
+ String8 address = String8(env->GetStringUTFChars((jstring) addrJobj, NULL));
+ AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
+ deviceVector.add(dev);
+ }
+
+ status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
+ return (jint) nativeToJavaStatus(status);
+}
+
+static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, jobject clazz,
+ jint uid) {
+
+ //###
+ status_t status = NO_ERROR;//AudioSystem::removeUidDeviceAffinities();
+ return (jint) nativeToJavaStatus(status);
+}
+
+
static jint
android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
{
@@ -2133,6 +2180,10 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_AudioSystem_getAudioHwSyncForSession},
{"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
(void *)android_media_AudioSystem_registerPolicyMixes},
+ {"setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+ (void *)android_media_AudioSystem_setUidDeviceAffinities},
+ {"removeUidDeviceAffinities", "(I)I",
+ (void *)android_media_AudioSystem_removeUidDeviceAffinities},
{"native_register_dynamic_policy_callback", "()V",
(void *)android_media_AudioSystem_registerDynPolicyCallback},
{"native_register_recording_callback", "()V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c745c160e143..6576587899be 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -348,6 +348,15 @@ static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactio
transaction->setInputWindowInfo(ctrl, *handle->getInfo());
}
+static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jobject fromTokenObj, jobject toTokenObj) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ sp<IBinder> fromToken(ibinderForJavaObject(env, fromTokenObj));
+ sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
+ transaction->transferTouchFocus(fromToken, toToken);
+}
+
static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jfloatArray fColor) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1032,7 +1041,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
{"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
(void*)nativeCaptureLayers },
{"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
- (void*)nativeSetInputWindowInfo },
+ (void*)nativeSetInputWindowInfo },
+ {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
+ (void*)nativeTransferTouchFocus },
{"nativeGetDisplayedContentSamplingAttributes",
"(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;",
(void*)nativeGetDisplayedContentSamplingAttributes },
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
index db4a4c4d836b..c35706501c3d 100644
--- a/core/proto/android/os/enums.proto
+++ b/core/proto/android/os/enums.proto
@@ -57,6 +57,7 @@ enum BatteryStatusEnum {
}
// These constants are defined in hardware/interfaces/thermal/1.0/types.hal
+// and in hardware/interfaces/thermal/2.0/types.hal
// They are primarily used by android/os/HardwarePropertiesManager.java.
// Any change to the types in the thermal hal should be made here as well.
enum TemperatureTypeEnum {
@@ -65,6 +66,16 @@ enum TemperatureTypeEnum {
TEMPERATURE_TYPE_GPU = 1;
TEMPERATURE_TYPE_BATTERY = 2;
TEMPERATURE_TYPE_SKIN = 3;
+ TEMPERATURE_TYPE_USB_PORT = 4;
+ TEMPERATURE_TYPE_POWER_AMPLIFIER = 5;
+
+ // Battery Charge Limit - virtual thermal sensors.
+ TEMPERATURE_TYPE_BCL_VOLTAGE = 6;
+ TEMPERATURE_TYPE_BCL_CURRENT = 7;
+ TEMPERATURE_TYPE_BCL_PERCENTAGE = 8;
+
+ // Neural Processing Unit.
+ TEMPERATURE_TYPE_NPU = 9;
}
// Wakelock types, primarily used by android/os/PowerManager.java.
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 11bd43b11977..a914369a036c 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -436,9 +436,11 @@ message GlobalSettingsProto {
// Ordered GPU debug layer list for GLES
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers_gles = 7;
- // App opt in to load updated graphics driver instead of
- // native graphcis driver through developer options.
- optional SettingProto updated_gfx_driver_dev_opt_in_app = 8;
+ // Apps opt in to load graphics driver from Game Update Package
+ // instead of native graphcis driver through developer options.
+ optional SettingProto gup_dev_opt_in_apps = 8;
+ // Apps on the black list that are forbidden to useGame Update Package.
+ optional SettingProto gup_black_list = 9;
}
optional Gpu gpu = 59;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 60561bd9dbc5..6f9a5649d4ac 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -82,6 +82,7 @@ message ActivityDisplayProto {
repeated ActivityStackProto stacks = 3;
optional int32 focused_stack_id = 4;
optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
+ optional bool single_task_instance = 6;
}
message ActivityStackProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c6343a8738d8..0778304d26aa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -42,6 +42,8 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_ROLLBACK_EXECUTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
@@ -3377,6 +3379,11 @@
<permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
android:protectionLevel="signature|installer|verifier" />
+ <!-- @SystemApi Allows the system to read runtime permission state.
+ @hide -->
+ <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to observe permission changes. -->
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature|privileged" />
@@ -3846,6 +3853,16 @@
<permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
android:protectionLevel="signature" />
+ <!-- @hide Rollback manager needs to have this permission before the PackageManager will
+ trust it to enable rollback.
+ -->
+ <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows managing apk level rollbacks. -->
+ <permission android:name="android.permission.MANAGE_ROLLBACKS"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
<permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
android:protectionLevel="signature|verifier" />
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 7dee2af3abbd..ded2b3569952 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -31,7 +31,7 @@
android:layout_alwaysShow="true"
android:elevation="8dp"
android:paddingStart="16dp"
- android:background="@color/white" >
+ android:background="?attr/colorBackgroundFloating" >
<TextView android:id="@+id/profile_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
@@ -73,7 +73,7 @@
android:id="@+id/resolver_list"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
- android:background="@color/white"
+ android:background="?attr/colorBackgroundFloating"
android:elevation="8dp"
android:listSelector="@color/transparent"
android:divider="@null"
@@ -84,7 +84,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
- android:background="@color/white"
+ android:background="?attr/colorBackgroundFloating"
android:text="@string/noApplications"
android:padding="32dp"
android:gravity="center"
diff --git a/core/res/res/values-land/dimens_permission_controller.xml b/core/res/res/values-land/dimens_permission_controller.xml
deleted file mode 100644
index 2146241fd830..000000000000
--- a/core/res/res/values-land/dimens_permission_controller.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<!-- Landscape dimensions for the permission grant dialog. -->
-<resources>
- <!-- Assuming the dimension of a sailfish, this yields 95% width in splitscreen and 65% in
- landscape -->
- <dimen name="permissionGrantDialogWeight">8.6</dimen>
- <dimen name="permissionGrantDialogWidth">334dp</dimen>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index c26bebe65a7a..0ae2b4d57be4 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -23,17 +23,4 @@
<integer name="config_mobile_mtu">1410</integer>
- <!-- Values for GPS configuration (Telus) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=3</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
deleted file mode 100644
index 96338b589cd2..000000000000
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Values for GPS configuration (Telus) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=3</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 79f4bb6fdd0b..ef32acd925d1 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -24,17 +24,4 @@
-->
<integer name="config_mobile_mtu">1410</integer>
- <!-- Values for GPS configuration (Rogers) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=2</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 10b007e9850d..2b78f5586fb8 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -22,17 +22,4 @@
-->
<integer name="config_mobile_mtu">1428</integer>
- <!-- Values for GPS configuration (Bell) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=2</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
deleted file mode 100644
index 657d1e77c4ab..000000000000
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Values for GPS configuration (Bell) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=2</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index ba8c75a179e9..7be9a1c5231f 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -24,17 +24,4 @@
-->
<integer name="config_mobile_mtu">1430</integer>
- <!-- Values for GPS configuration (Rogers) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=2</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-night/themes_permission_controller.xml b/core/res/res/values-night/themes_permission_controller.xml
deleted file mode 100644
index a071927f46b2..000000000000
--- a/core/res/res/values-night/themes_permission_controller.xml
+++ /dev/null
@@ -1,32 +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.
- -->
-
-<!-- themes for the permission grant dialog. -->
-<resources>
- <style name="Theme.DeviceDefault.PermissionGrantApp"
- parent="@style/Theme.DeviceDefault.Panel">
- <item name="windowIsFloating">false</item>
- <item name="windowTranslucentStatus">true</item>
- <item name="backgroundDimEnabled">true</item>
- <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
- </style>
-
- <style name="Theme.DeviceDefault.PermissionGrant"
- parent="@style/Theme.DeviceDefault.Dialog">
- <item name="titleTextStyle">@style/PermissionGrantTitleMessage</item>
- </style>
-</resources>
diff --git a/core/res/res/values-port/dimens_permission_controller.xml b/core/res/res/values-port/dimens_permission_controller.xml
deleted file mode 100644
index af28713e5ba2..000000000000
--- a/core/res/res/values-port/dimens_permission_controller.xml
+++ /dev/null
@@ -1,23 +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.
- -->
-
-<!-- portrait dimensions for the permission grant dialog. -->
-<resources>
- <!-- This yields 95% width -->
- <dimen name="permissionGrantDialogWeight">380</dimen>
- <dimen name="permissionGrantDialogWidth">0dp</dimen>
-</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 91faa5517860..183c2e8cf486 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3755,6 +3755,8 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity"/>
+ <!-- Secure Element which the AIDs should be routed to -->
+ <attr name="secureElementName"/>
</declare-styleable>
<!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dd51cb615d8a..54f6c632907f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1112,6 +1112,11 @@
resource] to be present in order to function. Default value is false. -->
<attr name="isSplitRequired" format="boolean" />
+ <!-- Flag to specify if this app prioritizes code integrity. The system may choose
+ to run with better integrity guarantee in various components if possible based on the app's
+ <code>targetSdkVersion</code>. -->
+ <attr name="preferCodeIntegrity" format="boolean" />
+
<!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or
{@code <application>} tag. If specified on the {@code <application>}
tag these will be considered defaults for all activities in the
@@ -1580,6 +1585,7 @@
to honor this flag as well. -->
<attr name="usesCleartextTraffic" />
<attr name="multiArch" />
+ <attr name="preferCodeIntegrity" />
<attr name="extractNativeLibs" />
<attr name="defaultToDeviceProtectedStorage" format="boolean" />
<attr name="directBootAware" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cb4f416b6539..e4abf8f4cf49 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -929,6 +929,9 @@
in hardware. -->
<bool name="config_setColorTransformAccelerated">false</bool>
+ <!-- Boolean indicating whether display white balance is supported. -->
+ <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
<!-- Control whether Night display is available. This should only be enabled on devices
that have a HWC implementation that can apply the matrix passed to setColorTransform
without impacting power, performance, and app compatibility (e.g. protected content). -->
@@ -2842,19 +2845,6 @@
<bool name="config_auto_attach_data_on_creation">true</bool>
- <!-- Values for GPS configuration -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>SUPL_HOST=supl.google.com</item>
- <item>SUPL_PORT=7275</item>
- <item>SUPL_VER=0x20000</item>
- <item>SUPL_MODE=1</item>
- <item>SUPL_ES=1</item>
- <item>LPP_PROFILE=0</item>
- <item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=3</item>
- </string-array>
-
<!-- Sprint need a 70 ms delay for 3way call -->
<integer name="config_cdma_3waycall_flash_delay">0</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d383362dfe86..a7bc57afa749 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3072,7 +3072,7 @@
<!-- Title of intent resolver dialog when selecting a viewer application that opens URI
and a previously used application is known [CHAR LIMIT=128]. -->
<string name="whichGiveAccessToApplicationNamed">Give access to open <xliff:g id="host" example="mail.google.com">%1$s</xliff:g> links with <xliff:g id="application" example="Gmail">%2$s</xliff:g></string>
- <!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=16] -->
+ <!-- Label for a link to an intent resolver dialog to open URI [CHAR LIMIT=18] -->
<string name="whichGiveAccessToApplicationLabel">Give access</string>
<!-- Title of intent resolver dialog when selecting an editor application to run. -->
<string name="whichEditApplication">Edit with</string>
@@ -4436,7 +4436,8 @@
<xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string>
<!-- Text spoken when accessibility shortcut warning dialog is shown. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_spoken_feedback">Use Accessibility Shortcut again to start the current accessibility feature</string>
+ <string name="accessibility_shortcut_spoken_feedback">Press and hold both volume keys for three seconds to use
+ <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g></string>
<!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. -->
<string name="accessibility_button_prompt_text">Choose a feature to use when you tap the Accessibility button:</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 7c95d1efb60d..200ef2f56f51 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -355,6 +355,30 @@ easier.
<item name="fontFamily">@string/config_bodyFontFamilyMedium</item>
</style>
<style name="TextAppearance.DeviceDefault.Widget.Toolbar.Title" parent="TextAppearance.DeviceDefault.Widget.ActionBar.Title"/>
+ <style name="TextAppearance.DeviceDefault.Widget.Toolbar.Subtitle" parent="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle"/>
+ <style name="TextAppearance.DeviceDefault.Body1" parent="TextAppearance.Material.Body1">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Body2" parent="TextAppearance.Material.Body2">
+ <item name="fontFamily">@string/config_bodyFontFamilyMedium</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Subhead" parent="TextAppearance.Material.Subhead">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Headline" parent="TextAppearance.Material.Headline">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Display1" parent="TextAppearance.Material.Display1">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Title" parent="TextAppearance.Material.Title">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Caption" parent="TextAppearance.Material.Caption">
+ <item name="fontFamily">@string/config_bodyFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead"/>
+ <style name="TextAppearance.DeviceDefault.ListItemSecondary" parent="TextAppearance.DeviceDefault.Body1"/>
<!-- Preference Styles -->
<style name="Preference.DeviceDefault" parent="Preference.Material"/>
diff --git a/core/res/res/values/styles_permission_controller.xml b/core/res/res/values/styles_permission_controller.xml
deleted file mode 100644
index 5a9d3e6c2889..000000000000
--- a/core/res/res/values/styles_permission_controller.xml
+++ /dev/null
@@ -1,98 +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.
- -->
-
-<resources>
- <!-- styles for the permission grant dialog. -->
- <style name="PermissionGrantDialog">
- <item name="background">?attr/windowBackground</item>
- <item name="elevation">?attr/windowElevation</item>
- <item name="layout_weight">@dimen/permissionGrantDialogWeight</item>
- <item name="layout_width">@dimen/permissionGrantDialogWidth</item>
- </style>
-
- <style name="PermissionGrantTitleIcon">
- <item name="layout_width">24dp</item>
- <item name="layout_height">24dp</item>
- <item name="layout_marginBottom">12dp</item>
- <item name="tint">?attr/colorAccent</item>
- <item name="scaleType">fitCenter</item>
- </style>
-
- <style name="PermissionGrantTitleMessage"
- parent="@style/TextAppearance.DeviceDefault">
- <item name="gravity">center</item>
- <item name="textSize">20sp</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="PermissionGrantIndex"
- parent="@style/TextAppearance.DeviceDefault">
- <item name="paddingEnd">12dp</item>
- <item name="singleLine">true</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="PermissionGrantDescription">
- <item name="layout_marginStart">24dp</item>
- <item name="layout_marginEnd">24dp</item>
- </style>
-
- <style name="PermissionGrantContent">
- <item name="layout_marginStart">24dp</item>
- <item name="layout_marginEnd">24dp</item>
- </style>
-
- <style name="PermissionGrantDetailMessage"
- parent="@style/TextAppearance.DeviceDefault">
- <item name="layout_marginTop">18dp</item>
- <item name="textColor">?attr/textColorPrimary</item>
- <item name="textSize">16sp</item>
- </style>
-
- <!-- styles for the permission review screen. -->
- <style name="PermissionReviewDescription">
- <item name="layout_marginTop">20dp</item>
- <item name="layout_marginStart">24dp</item>
- <item name="layout_marginBottom">16dp</item>
- <item name="layout_marginEnd">24dp</item>
- </style>
-
- <style name="PermissionReviewTitleIcon">
- <item name="layout_marginTop">4dp</item>
- <item name="layout_width">36dp</item>
- <item name="layout_height">36dp</item>
- <item name="scaleType">fitCenter</item>
- </style>
-
- <style name="PermissionReviewTitleMessage"
- parent="@style/TextAppearance.DeviceDefault">
- <item name="paddingStart">22dp</item>
- <item name="textSize">20sp</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="PermissionReviewSettings">
- <item name="layout_marginStart">8dp</item>
- <item name="layout_marginEnd">8dp</item>
- </style>
-
- <style name="PermissionReviewButtonBar">
- <item name="layout_marginStart">24dp</item>
- <item name="layout_marginEnd">16dp</item>
- <item name="layout_marginBottom">4dp</item>
- </style>
-</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a4a97d33ee65..e8cbf666c03c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1269,7 +1269,6 @@
<java-symbol type="array" name="config_telephonyEuiccDeviceCapabilities" />
<java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="array" name="config_keySystemUuidMapping" />
- <java-symbol type="array" name="config_gpsParameters" />
<java-symbol type="array" name="required_apps_managed_user" />
<java-symbol type="array" name="required_apps_managed_profile" />
<java-symbol type="array" name="required_apps_managed_device" />
@@ -3029,6 +3028,7 @@
<java-symbol type="drawable" name="ic_doc_generic" />
<java-symbol type="bool" name="config_setColorTransformAccelerated" />
+ <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
<java-symbol type="bool" name="config_nightDisplayAvailable" />
<java-symbol type="bool" name="config_allowDisablingAssistDisclosure" />
<java-symbol type="integer" name="config_defaultNightDisplayAutoMode" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 56265cc04c0c..0f4ca66dcd68 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -68,6 +68,10 @@ easier.
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.DeviceDefault.ListItem</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.DeviceDefault.ListItem</item>
+ <item name="textAppearanceListItemSecondary">@style/TextAppearance.DeviceDefault.ListItemSecondary</item>
+
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonStyle">@style/Widget.DeviceDefault.Button</item>
@@ -783,7 +787,6 @@ easier.
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
-
<item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
<item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
<item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
@@ -792,11 +795,12 @@ easier.
<item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
<item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
<item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
-
<item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
-
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.DeviceDefault.ListItem</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.DeviceDefault.ListItem</item>
+ <item name="textAppearanceListItemSecondary">@style/TextAppearance.DeviceDefault.ListItemSecondary</item>
<!-- Button styles -->
<item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
@@ -1439,19 +1443,23 @@ easier.
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
- <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault.Light">
+ <!-- From Theme.Material.Light.LightStatusBar -->
+ <item name="windowLightStatusBar">true</item>
+
+ <!-- From Theme.Material.Settings -->
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_material_settings</item>
+ <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
+ <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
+ <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
+
<!-- action bar -->
- <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
<item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar</item>
<item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
<!-- Color palette -->
- <item name="colorBackground">@color/background_device_default_light</item>
- <item name="colorPrimary">@color/primary_device_default_settings_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
- <item name="colorAccent">@color/accent_device_default_light</item>
- <item name="colorError">@color/error_color_device_default_light</item>
<item name="colorEdgeEffect">@android:color/black</item>
<!-- Add white nav bar with divider that matches material -->
@@ -1459,24 +1467,9 @@ easier.
<item name="navigationBarColor">@android:color/white</item>
<item name="windowLightNavigationBar">true</item>
- <!-- Dialog attributes -->
- <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
- <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
-
- <!-- Text styles -->
- <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
-
<!-- Button styles -->
- <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
<item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
- <!-- Progress bar attributes -->
- <item name="colorProgressBackgroundNormal">@color/config_progress_background_tint</item>
- <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
-
- <!-- Toolbar attributes -->
- <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
-
<item name="listDivider">@color/list_divider_color_light</item>
</style>
diff --git a/core/res/res/values/themes_permission_controller.xml b/core/res/res/values/themes_permission_controller.xml
deleted file mode 100644
index 205c4eb2d9a2..000000000000
--- a/core/res/res/values/themes_permission_controller.xml
+++ /dev/null
@@ -1,40 +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.
- -->
-
-<resources>
- <!-- themes for the permission grant dialog. -->
- <style name="Theme.DeviceDefault.PermissionGrantApp"
- parent="@style/Theme.DeviceDefault.Light.Panel">
- <item name="windowIsFloating">false</item>
- <item name="windowTranslucentStatus">true</item>
- <item name="backgroundDimEnabled">true</item>
- <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
- </style>
-
- <style name="Theme.DeviceDefault.PermissionGrant"
- parent="@style/Theme.DeviceDefault.Light.Dialog">
- <item name="titleTextStyle">@style/PermissionGrantTitleMessage</item>
- </style>
-
- <!-- themes for the permission review dialog. -->
- <style name="Theme.DeviceDefault.PermissionReviewApp"
- parent="@style/Theme.DeviceDefault.Settings">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- <item name="titleTextStyle">@style/PermissionReviewTitleMessage</item>
- </style>
-</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f8bd4e33ec75..ac57d20a438a 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -475,7 +475,8 @@ public class SettingsBackupTest {
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
- Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
+ Settings.Global.GUP_DEV_OPT_IN_APPS,
+ Settings.Global.GUP_BLACK_LIST,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index d41a718147f2..9807f26ad367 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -20,8 +20,13 @@ import static android.view.InsetsState.INSET_SIDE_BOTTOM;
import static android.view.InsetsState.INSET_SIDE_TOP;
import static android.view.InsetsState.TYPE_IME;
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.TYPE_SIDE_BAR_1;
+import static android.view.InsetsState.TYPE_SIDE_BAR_2;
+import static android.view.InsetsState.TYPE_SIDE_BAR_3;
import static android.view.InsetsState.TYPE_TOP_BAR;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNotEquals;
import android.graphics.Rect;
@@ -133,4 +138,13 @@ public class InsetsStateTest {
p.recycle();
assertEquals(mState, mState2);
}
+
+ @Test
+ public void testGetDefaultVisibility() {
+ assertTrue(InsetsState.getDefaultVisibly(TYPE_TOP_BAR));
+ assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_1));
+ assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_2));
+ assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_3));
+ assertFalse(InsetsState.getDefaultVisibly(TYPE_IME));
+ }
}
diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk
index 5e518b60a9ee..ce7cb181b53a 100644
--- a/core/tests/featureflagtests/Android.mk
+++ b/core/tests/featureflagtests/Android.mk
@@ -9,7 +9,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib androidx.test.rules
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests
LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/core/tests/featureflagtests/AndroidManifest.xml b/core/tests/featureflagtests/AndroidManifest.xml
index b8ffacbe5aa8..326374e47702 100644
--- a/core/tests/featureflagtests/AndroidManifest.xml
+++ b/core/tests/featureflagtests/AndroidManifest.xml
@@ -26,7 +26,7 @@
</application>
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.coretests.featureflagtests"
android:label="Frameworks FeatureFlagUtils Tests" />
diff --git a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
index 0b1b333a1ddc..316042874201 100644
--- a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
+++ b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
@@ -24,10 +24,11 @@ import static junit.framework.Assert.assertTrue;
import android.content.Context;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6821282bd0a7..3342fd22caab 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -25,6 +25,7 @@ import android.annotation.Px;
import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontVariationAxis;
+import android.os.Build;
import android.os.LocaleList;
import android.text.GraphicsOperations;
import android.text.SpannableString;
@@ -69,7 +70,7 @@ public class Paint {
private MaskFilter mMaskFilter;
private PathEffect mPathEffect;
private Shader mShader;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Typeface mTypeface;
private Xfermode mXfermode;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 10f6fae3cf6d..77e77c49973c 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -29,6 +29,7 @@ import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
+import android.os.Build;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
@@ -736,7 +737,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
mOwner = owner;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 9361c7c29bcb..213ed7d1ff0a 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -345,7 +346,7 @@ public class KeyStore {
return list(prefix, UID_SELF);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean reset() {
try {
return mBinder.reset() == NO_ERROR;
@@ -413,7 +414,7 @@ public class KeyStore {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isEmpty() {
return isEmpty(UserHandle.myUserId());
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 7e69e3a8a73f..96798f978465 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -61,6 +61,7 @@ cc_defaults {
"libstatslog",
"libutils",
"libEGL",
+ "libGLESv1_CM",
"libGLESv2",
"libGLESv3",
"libvulkan",
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index bd1e6c5bf2e8..14e3a32817a0 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -41,14 +41,10 @@ X(DrawImage)
X(DrawImageNine)
X(DrawImageRect)
X(DrawImageLattice)
-X(DrawText)
-X(DrawPosText)
-X(DrawPosTextH)
-X(DrawTextRSXform)
X(DrawTextBlob)
X(DrawPatch)
X(DrawPoints)
X(DrawVertices)
X(DrawAtlas)
X(DrawShadowRec)
-X(DrawVectorDrawable) \ No newline at end of file
+X(DrawVectorDrawable)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4de25f93c592..6dc9d34cc3fd 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -373,61 +373,6 @@ struct DrawImageLattice final : Op {
}
};
-struct DrawText final : Op {
- static const auto kType = Type::DrawText;
- DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint)
- : bytes(bytes), x(x), y(y), paint(paint) {}
- size_t bytes;
- SkScalar x, y;
- SkPaint paint;
- void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawText(pod<void>(this), bytes, x, y, paint);
- }
-};
-struct DrawPosText final : Op {
- static const auto kType = Type::DrawPosText;
- DrawPosText(size_t bytes, const SkPaint& paint, int n) : bytes(bytes), paint(paint), n(n) {}
- size_t bytes;
- SkPaint paint;
- int n;
- void draw(SkCanvas* c, const SkMatrix&) const {
- auto points = pod<SkPoint>(this);
- auto text = pod<void>(this, n * sizeof(SkPoint));
- c->drawPosText(text, bytes, points, paint);
- }
-};
-struct DrawPosTextH final : Op {
- static const auto kType = Type::DrawPosTextH;
- DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n)
- : bytes(bytes), y(y), paint(paint), n(n) {}
- size_t bytes;
- SkScalar y;
- SkPaint paint;
- int n;
- void draw(SkCanvas* c, const SkMatrix&) const {
- auto xs = pod<SkScalar>(this);
- auto text = pod<void>(this, n * sizeof(SkScalar));
- c->drawPosTextH(text, bytes, xs, y, paint);
- }
-};
-struct DrawTextRSXform final : Op {
- static const auto kType = Type::DrawTextRSXform;
- DrawTextRSXform(size_t bytes, int xforms, const SkRect* cull, const SkPaint& paint)
- : bytes(bytes), xforms(xforms), paint(paint) {
- if (cull) {
- this->cull = *cull;
- }
- }
- size_t bytes;
- int xforms;
- SkRect cull = kUnset;
- SkPaint paint;
- void draw(SkCanvas* c, const SkMatrix&) const {
- // For alignment, the SkRSXforms are first in the pod section, followed by the text.
- c->drawTextRSXform(pod<void>(this, xforms * sizeof(SkRSXform)), bytes, pod<SkRSXform>(this),
- maybe_unset(cull), paint);
- }
-};
struct DrawTextBlob final : Op {
static const auto kType = Type::DrawTextBlob;
DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
@@ -682,33 +627,6 @@ void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanva
fs);
}
-void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
- copy_v(pod, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[],
- const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n);
- copy_v(pod, pos, n, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y,
- const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n);
- copy_v(pod, xs, n, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[],
- const SkRect* cull, const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint);
- copy_v(pod, xforms, n, (const char*)text, bytes);
- mHasText = true;
-}
void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
this->push<DrawTextBlob>(0, blob, x, y, paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index ae3c4f057c12..caaef67f724f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -101,10 +101,6 @@ private:
void drawDrawable(SkDrawable*, const SkMatrix*);
void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
- void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&);
- void drawPosText(const void*, size_t, const SkPoint[], const SkPaint&);
- void drawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&);
- void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&);
void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 83b9e7f6a3b8..ab95e69c4e26 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -710,6 +710,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
const SkPaint& paint, const SkPath& path, size_t start,
size_t end) {
+ SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
SkPaint paintCopy(paint);
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
@@ -717,9 +718,10 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
const int N = end - start;
- SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
- SkRSXform* xform = (SkRSXform*)storage.get();
- uint16_t* glyphs = (uint16_t*)(xform + N);
+ SkTextBlobBuilder builder;
+ auto rec = builder.allocRunRSXform(font, N);
+ SkRSXform* xform = (SkRSXform*)rec.pos;
+ uint16_t* glyphs = rec.glyphs;
SkPathMeasure meas(path, false);
for (size_t i = start; i < end; i++) {
@@ -740,7 +742,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
}
- this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy);
+ this->asSkCanvas()->drawTextBlob(builder.make(), 0, 0, paintCopy);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 20e77b453706..5b7ae70e821c 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -37,7 +37,8 @@ RenderMode WebViewFunctor_queryPlatformRenderMode() {
}
}
-int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode) {
+int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype,
+ RenderMode functorMode) {
if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) {
ALOGW("Unknown rendermode %d", (int)functorMode);
return -1;
@@ -47,7 +48,7 @@ int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode f
ALOGW("Unable to map from GLES platform to a vulkan functor");
return -1;
}
- return WebViewFunctorManager::instance().createFunctor(prototype, functorMode);
+ return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode);
}
void WebViewFunctor_release(int functor) {
@@ -56,7 +57,9 @@ void WebViewFunctor_release(int functor) {
static std::atomic_int sNextId{1};
-WebViewFunctor::WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) {
+WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
+ RenderMode functorMode)
+ : mData(data) {
mFunctor = sNextId++;
mCallbacks = callbacks;
mMode = functorMode;
@@ -66,12 +69,12 @@ WebViewFunctor::~WebViewFunctor() {
destroyContext();
ATRACE_NAME("WebViewFunctor::onDestroy");
- mCallbacks.onDestroyed(mFunctor);
+ mCallbacks.onDestroyed(mFunctor, mData);
}
void WebViewFunctor::sync(const WebViewSyncData& syncData) const {
ATRACE_NAME("WebViewFunctor::sync");
- mCallbacks.onSync(mFunctor, syncData);
+ mCallbacks.onSync(mFunctor, mData, syncData);
}
void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
@@ -79,14 +82,14 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
if (!mHasContext) {
mHasContext = true;
}
- mCallbacks.gles.draw(mFunctor, drawInfo);
+ mCallbacks.gles.draw(mFunctor, mData, drawInfo);
}
void WebViewFunctor::destroyContext() {
if (mHasContext) {
mHasContext = false;
ATRACE_NAME("WebViewFunctor::onContextDestroyed");
- mCallbacks.onContextDestroyed(mFunctor);
+ mCallbacks.onContextDestroyed(mFunctor, mData);
}
}
@@ -95,9 +98,9 @@ WebViewFunctorManager& WebViewFunctorManager::instance() {
return sInstance;
}
-int WebViewFunctorManager::createFunctor(const WebViewFunctorCallbacks& callbacks,
+int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
RenderMode functorMode) {
- auto object = std::make_unique<WebViewFunctor>(callbacks, functorMode);
+ auto object = std::make_unique<WebViewFunctor>(data, callbacks, functorMode);
int id = object->id();
auto handle = object->createHandle();
{
@@ -164,4 +167,4 @@ sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) {
return nullptr;
}
-} // namespace android::uirenderer \ No newline at end of file
+} // namespace android::uirenderer
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 2a621dd411e3..1719ce7cca75 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -29,7 +29,7 @@ class WebViewFunctorManager;
class WebViewFunctor {
public:
- WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+ WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
~WebViewFunctor();
class Handle : public LightRefBase<Handle> {
@@ -63,6 +63,7 @@ public:
private:
WebViewFunctorCallbacks mCallbacks;
+ void* const mData;
int mFunctor;
RenderMode mMode;
bool mHasContext = false;
@@ -73,7 +74,7 @@ class WebViewFunctorManager {
public:
static WebViewFunctorManager& instance();
- int createFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+ int createFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
void releaseFunctor(int functor);
void onContextDestroyed();
void destroyFunctor(int functor);
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index e5346aabaee3..da3d06a4d60c 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -17,6 +17,7 @@
#ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
#define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
+#include <cutils/compiler.h>
#include <private/hwui/DrawGlInfo.h>
namespace android::uirenderer {
@@ -27,7 +28,7 @@ enum class RenderMode {
};
// Static for the lifetime of the process
-RenderMode WebViewFunctor_queryPlatformRenderMode();
+ANDROID_API RenderMode WebViewFunctor_queryPlatformRenderMode();
struct WebViewSyncData {
bool applyForceDark;
@@ -35,21 +36,21 @@ struct WebViewSyncData {
struct WebViewFunctorCallbacks {
// kModeSync, called on RenderThread
- void (*onSync)(int functor, const WebViewSyncData& syncData);
+ void (*onSync)(int functor, void* data, const WebViewSyncData& syncData);
// Called when either the context is destroyed _or_ when the functor's last reference goes
// away. Will always be called with an active context and always on renderthread.
- void (*onContextDestroyed)(int functor);
+ void (*onContextDestroyed)(int functor, void* data);
// Called when the last reference to the handle goes away and the handle is considered
// irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if
// this functor had ever been drawn.
- void (*onDestroyed)(int functor);
+ void (*onDestroyed)(int functor, void* data);
union {
struct {
// Called on RenderThread. initialize is guaranteed to happen before this call
- void (*draw)(int functor, const DrawGlInfo& params);
+ void (*draw)(int functor, void* data, const DrawGlInfo& params);
} gles;
// TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
// what params are valid on what callbacks
@@ -70,12 +71,12 @@ struct WebViewFunctorCallbacks {
// Creates a new WebViewFunctor from the given prototype. The prototype is copied after
// this function returns. Caller retains full ownership of it.
// Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination)
-int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
+ANDROID_API int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is released,
// and it should be considered alive & active until that point.
-void WebViewFunctor_release(int functor);
+ANDROID_API void WebViewFunctor_release(int functor);
} // namespace android::uirenderer
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 5ff8993e6779..6a1ca5a25361 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -315,24 +315,24 @@ public:
static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
auto callbacks = WebViewFunctorCallbacks{
.onSync =
- [](int functor, const WebViewSyncData& data) {
+ [](int functor, void* client_data, const WebViewSyncData& data) {
expectOnRenderThread();
sMockFunctorCounts[functor].sync++;
},
.onContextDestroyed =
- [](int functor) {
+ [](int functor, void* client_data) {
expectOnRenderThread();
sMockFunctorCounts[functor].contextDestroyed++;
},
.onDestroyed =
- [](int functor) {
+ [](int functor, void* client_data) {
expectOnRenderThread();
sMockFunctorCounts[functor].destroyed++;
},
};
switch (mode) {
case RenderMode::OpenGL_ES:
- callbacks.gles.draw = [](int functor, const DrawGlInfo& params) {
+ callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
expectOnRenderThread();
sMockFunctorCounts[functor].glesDraw++;
};
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index 9a1ee54bff49..4111bd24847e 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -16,7 +16,7 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
-
+#include <SkFont.h>
#include <cstdio>
class ListViewAnimation;
@@ -46,11 +46,13 @@ class ListViewAnimation : public TestListViewSceneBase {
SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
128 * 3;
paint.setColor(bgDark ? Color::White : Color::Grey_700);
- paint.setTextSize(size / 2);
+
+ SkFont font;
+ font.setSize(size / 2);
char charToShow = 'A' + (rand() % 26);
- const SkPoint pos[] = {{SkIntToScalar(size / 2),
- /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
- canvas.drawPosText(&charToShow, 1, pos, paint);
+ const SkPoint pos = {SkIntToScalar(size / 2),
+ /*approximate centering*/ SkFloatToScalar(size * 0.7f)};
+ canvas.drawSimpleText(&charToShow, 1, kUTF8_SkTextEncoding, pos.fX, pos.fY, font, paint);
return bitmap;
}
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 53bf84f13fd6..1b4cf7e144bd 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -100,8 +100,8 @@ TEST(SkiaDisplayList, syncContexts) {
GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
skiaDL.mChildFunctors.push_back(&functorDrawable);
- int functor2 = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
- RenderMode::OpenGL_ES);
+ int functor2 = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
auto& counts = TestUtils::countsForFunctor(functor2);
skiaDL.mChildFunctors.push_back(
skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas));
diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
index c8169aff1c5e..e1fb8b7069ff 100644
--- a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
+++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
@@ -27,8 +27,8 @@ using namespace android;
using namespace android::uirenderer;
TEST(WebViewFunctor, createDestroyGLES) {
- int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
- RenderMode::OpenGL_ES);
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
WebViewFunctor_release(functor);
TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
@@ -41,8 +41,8 @@ TEST(WebViewFunctor, createDestroyGLES) {
}
TEST(WebViewFunctor, createSyncHandleGLES) {
- int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
- RenderMode::OpenGL_ES);
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -82,8 +82,8 @@ TEST(WebViewFunctor, createSyncHandleGLES) {
}
TEST(WebViewFunctor, createSyncDrawGLES) {
- int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
- RenderMode::OpenGL_ES);
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -109,8 +109,8 @@ TEST(WebViewFunctor, createSyncDrawGLES) {
}
TEST(WebViewFunctor, contextDestroyed) {
- int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
- RenderMode::OpenGL_ES);
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
ASSERT_NE(-1, functor);
auto handle = WebViewFunctorManager::instance().handleFor(functor);
ASSERT_TRUE(handle);
@@ -151,4 +151,4 @@ TEST(WebViewFunctor, contextDestroyed) {
EXPECT_EQ(2, counts.glesDraw);
EXPECT_EQ(2, counts.contextDestroyed);
EXPECT_EQ(1, counts.destroyed);
-} \ No newline at end of file
+}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index d90a597b1cbb..609a15e1be7e 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -17,6 +17,7 @@
package android.location;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.util.SparseArray;
import java.util.Iterator;
@@ -207,7 +208,7 @@ public final class GpsStatus {
status.mAzimuths);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
void setTimeToFirstFix(int ttff) {
mTimeToFirstFix = ttff;
}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 70a97e1f7da0..fbebbb11ffd5 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -19,6 +19,7 @@ package android.location;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -124,7 +125,7 @@ public class Location implements Parcelable {
}
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mProvider;
private long mTime = 0;
@UnsupportedAppUsage
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 040e4f9f1bd0..d96597bb3b69 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2372,7 +2372,7 @@ public class LocationManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean sendNiResponse(int notifId, int userResponse) {
try {
return mService.sendNiResponse(notifId, userResponse);
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 2d7f7e309004..154bd563fb0f 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -18,6 +18,7 @@ package android.location;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -142,19 +143,19 @@ public final class LocationRequest implements Parcelable {
*/
private static final double FASTEST_INTERVAL_FACTOR = 6.0; // 6x
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mQuality = POWER_LOW;
@UnsupportedAppUsage
private long mInterval = 60 * 60 * 1000; // 60 minutes
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR); // 10 minutes
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mExplicitFastestInterval = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private long mExpireAt = Long.MAX_VALUE; // no expiry
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mNumUpdates = Integer.MAX_VALUE; // no expiry
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private float mSmallestDisplacement = 0.0f; // meters
@UnsupportedAppUsage
private WorkSource mWorkSource = null;
@@ -603,14 +604,14 @@ public final class LocationRequest implements Parcelable {
return mHideFromAppOps;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void checkInterval(long millis) {
if (millis < 0) {
throw new IllegalArgumentException("invalid interval: " + millis);
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void checkQuality(int quality) {
switch (quality) {
case ACCURACY_FINE:
@@ -625,14 +626,14 @@ public final class LocationRequest implements Parcelable {
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void checkDisplacement(float meters) {
if (meters < 0.0f) {
throw new IllegalArgumentException("invalid displacement: " + meters);
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void checkProvider(String name) {
if (name == null) {
throw new IllegalArgumentException("invalid provider: " + name);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index da52a268e384..30b5480fba55 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -67,6 +67,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -539,37 +540,42 @@ public class AudioManager {
/**
* Adjusting the volume due to a hardware key press.
+ * This flag can be used in the places in order to denote (or check) that a volume adjustment
+ * request is from a hardware key press. (e.g. {@link MediaController}).
* @hide
*/
@SystemApi
- public static final int FLAG_FROM_KEY = 1 << 12;
-
- private static final String[] FLAG_NAMES = {
- "FLAG_SHOW_UI",
- "FLAG_ALLOW_RINGER_MODES",
- "FLAG_PLAY_SOUND",
- "FLAG_REMOVE_SOUND_AND_VIBRATE",
- "FLAG_VIBRATE",
- "FLAG_FIXED_VOLUME",
- "FLAG_BLUETOOTH_ABS_VOLUME",
- "FLAG_SHOW_SILENT_HINT",
- "FLAG_HDMI_SYSTEM_AUDIO_VOLUME",
- "FLAG_ACTIVE_MEDIA_ONLY",
- "FLAG_SHOW_UI_WARNINGS",
- "FLAG_SHOW_VIBRATE_HINT",
- "FLAG_FROM_KEY",
- };
+ public static final int FLAG_FROM_KEY = 1 << 16;
+
+ // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
+ private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
+
+ static {
+ FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
+ FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
+ FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
+ FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
+ FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
+ FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
+ FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
+ FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
+ FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
+ FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
+ FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
+ FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
+ FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
+ }
/** @hide */
public static String flagsToString(int flags) {
final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < FLAG_NAMES.length; i++) {
- final int flag = 1 << i;
+ for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
+ final int flag = entry.getKey();
if ((flags & flag) != 0) {
if (sb.length() > 0) {
sb.append(',');
}
- sb.append(FLAG_NAMES[i]);
+ sb.append(entry.getValue());
flags &= ~flag;
}
}
@@ -4274,9 +4280,8 @@ public class AudioManager {
* Return codes for listAudioPorts(), createAudioPatch() ...
*/
- /** @hide
- * CANDIDATE FOR PUBLIC API
- */
+ /** @hide */
+ @SystemApi
public static final int SUCCESS = AudioSystem.SUCCESS;
/**
* A default error code.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 58fc1ab1c4dd..45cde0ffecc4 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -916,6 +916,13 @@ public class AudioSystem
public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
+ /** see AudioPolicy.setUidDeviceAffinities() */
+ public static native int setUidDeviceAffinities(int uid, @NonNull int[] types,
+ @NonNull String[] addresses);
+
+ /** see AudioPolicy.removeUidDeviceAffinities() */
+ public static native int removeUidDeviceAffinities(int uid);
+
public static native int systemReady();
public static native float getStreamVolumeDB(int stream, int index, int device);
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index aa123bdc9cff..4f74ec911499 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -19,6 +19,7 @@ package android.media;
import android.annotation.UnsupportedAppUsage;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
+import android.os.Build;
/**
* Retrieves the
@@ -496,7 +497,7 @@ public class CamcorderProfile
}
// Methods implemented by JNI
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static native final void native_init();
@UnsupportedAppUsage
private static native final CamcorderProfile native_get_camcorder_profile(
diff --git a/media/java/android/media/Controller2Link.aidl b/media/java/android/media/Controller2Link.aidl
new file mode 100644
index 000000000000..64edafcb11fc
--- /dev/null
+++ b/media/java/android/media/Controller2Link.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable Controller2Link;
diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java
new file mode 100644
index 000000000000..a62db5f1fb20
--- /dev/null
+++ b/media/java/android/media/Controller2Link.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+import java.util.Objects;
+
+/**
+ * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
+ * @hide
+ */
+// @SystemApi
+public final class Controller2Link implements Parcelable {
+ private static final String TAG = "Controller2Link";
+ private static final boolean DEBUG = MediaController2.DEBUG;
+
+ public static final Parcelable.Creator<Controller2Link> CREATOR =
+ new Parcelable.Creator<Controller2Link>() {
+ @Override
+ public Controller2Link createFromParcel(Parcel in) {
+ return new Controller2Link(in);
+ }
+
+ @Override
+ public Controller2Link[] newArray(int size) {
+ return new Controller2Link[size];
+ }
+ };
+
+
+ private final MediaController2 mController;
+ private final IMediaController2 mIController;
+
+ public Controller2Link(MediaController2 controller) {
+ mController = controller;
+ mIController = new Controller2Stub();
+ }
+
+ Controller2Link(Parcel in) {
+ mController = null;
+ mIController = IMediaController2.Stub.asInterface(in.readStrongBinder());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mIController.asBinder());
+ }
+
+ @Override
+ public int hashCode() {
+ return mIController.asBinder().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Controller2Link)) {
+ return false;
+ }
+ Controller2Link other = (Controller2Link) obj;
+ return Objects.equals(mIController.asBinder(), other.mIController.asBinder());
+ }
+
+ /** Interface method for IMediaController2.notifyConnected */
+ public void notifyConnected(int seq, Bundle connectionResult) {
+ try {
+ mIController.notifyConnected(seq, connectionResult);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaController2.notifyDisonnected */
+ public void notifyDisconnected(int seq) {
+ try {
+ mIController.notifyDisconnected(seq);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaController2.sendSessionCommand */
+ public void sendSessionCommand(int seq, Session2Command command, Bundle args,
+ ResultReceiver resultReceiver) {
+ try {
+ mIController.sendSessionCommand(seq, command, args, resultReceiver);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaController2.cancelSessionCommand */
+ public void cancelSessionCommand(int seq) {
+ try {
+ mIController.cancelSessionCommand(seq);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Stub implementation for IMediaController2.notifyConnected */
+ public void onConnected(int seq, Bundle connectionResult) {
+ if (connectionResult == null) {
+ onDisconnected(seq);
+ return;
+ }
+ mController.onConnected(seq, connectionResult);
+ }
+
+ /** Stub implementation for IMediaController2.notifyDisonnected */
+ public void onDisconnected(int seq) {
+ mController.onDisconnected(seq);
+ }
+
+ /** Stub implementation for IMediaController2.sendSessionCommand */
+ public void onSessionCommand(int seq, Session2Command command, Bundle args,
+ ResultReceiver resultReceiver) {
+ mController.onSessionCommand(seq, command, args, resultReceiver);
+ }
+
+ /** Stub implementation for IMediaController2.cancelSessionCommand */
+ public void onCancelCommand(int seq) {
+ mController.onCancelCommand(seq);
+ }
+
+ private class Controller2Stub extends IMediaController2.Stub {
+ @Override
+ public void notifyConnected(int seq, Bundle connectionResult) {
+ Controller2Link.this.onConnected(seq, connectionResult);
+ }
+
+ @Override
+ public void notifyDisconnected(int seq) {
+ Controller2Link.this.onDisconnected(seq);
+ }
+
+ @Override
+ public void sendSessionCommand(int seq, Session2Command command, Bundle args,
+ ResultReceiver resultReceiver) {
+ Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
+ }
+
+ @Override
+ public void cancelSessionCommand(int seq) {
+ Controller2Link.this.onCancelCommand(seq);
+ }
+ }
+}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 32c4643adad0..b9088d417dad 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -24,6 +24,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -469,7 +470,7 @@ public class ExifInterface {
// See http://www.exiv2.org/makernote.html#R11
private static final int PEF_MAKER_NOTE_SKIP_SIZE = 6;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static SimpleDateFormat sFormatter;
// See Exchangeable image file format for digital still cameras: Exif version 2.2.
@@ -1303,7 +1304,7 @@ public class ExifInterface {
sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mFilename;
private final FileDescriptor mSeekableFileDescriptor;
private final AssetManager.AssetInputStream mAssetInputStream;
@@ -1313,7 +1314,7 @@ public class ExifInterface {
private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
private Set<Integer> mAttributesOffsets = new HashSet<>(EXIF_TAGS.length);
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mHasThumbnail;
// The following values used for indicating a thumbnail position.
private int mThumbnailOffset;
@@ -2177,7 +2178,7 @@ public class ExifInterface {
}
/** {@hide} */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static float convertRationalLatLonToFloat(String rationalString, String ref) {
try {
String [] parts = rationalString.split(",");
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index abd64119de61..9fbd7eac6e8a 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -223,6 +223,11 @@ interface IAudioService {
boolean isAudioServerRunning();
+ int setUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid, in int[] deviceTypes,
+ in String[] deviceAddresses);
+
+ int removeUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid);
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/IMediaController2.aidl b/media/java/android/media/IMediaController2.aidl
new file mode 100644
index 000000000000..ca5394f504cb
--- /dev/null
+++ b/media/java/android/media/IMediaController2.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.media.Session2Command;
+
+/**
+ * Interface from MediaSession2 to MediaController2.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from session to make session owner(s) frozen.
+ * @hide
+ */
+ // Code for AML only
+oneway interface IMediaController2 {
+ void notifyConnected(int seq, in Bundle connectionResult) = 0;
+ void notifyDisconnected(int seq) = 1;
+ void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
+ in ResultReceiver resultReceiver) = 2;
+ void cancelSessionCommand(int seq) = 3;
+ // Next Id : 4
+}
diff --git a/media/java/android/media/IMediaSession2.aidl b/media/java/android/media/IMediaSession2.aidl
new file mode 100644
index 000000000000..26e717b39afc
--- /dev/null
+++ b/media/java/android/media/IMediaSession2.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.media.Controller2Link;
+import android.media.Session2Command;
+
+/**
+ * Interface from MediaController2 to MediaSession2.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from session to make session owner(s) frozen.
+ * @hide
+ */
+ // Code for AML only
+oneway interface IMediaSession2 {
+ void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
+ void disconnect(in Controller2Link caller, int seq) = 1;
+ void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand,
+ in Bundle args, in ResultReceiver resultReceiver) = 2;
+ void cancelSessionCommand(in Controller2Link caller, int seq) = 3;
+ // Next Id : 4
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 902582905b0e..10a1e3a72225 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -972,7 +972,7 @@ public final class MediaCodecInfo {
* {@code null}. The array is sorted in ascending order.
*/
public int[] getSupportedSampleRates() {
- return Arrays.copyOf(mSampleRates, mSampleRates.length);
+ return mSampleRates != null ? Arrays.copyOf(mSampleRates, mSampleRates.length) : null;
}
/**
diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java
new file mode 100644
index 000000000000..275b0acd8ad6
--- /dev/null
+++ b/media/java/android/media/MediaConstants.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+class MediaConstants {
+ // Bundle key for int
+ static final String KEY_PID = "android.media.key.PID";
+
+ // Bundle key for String
+ static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
+
+ // Bundle key for Parcelable
+ static final String KEY_SESSION2_STUB = "android.media.key.SESSION2_STUB";
+ static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
+
+ private MediaConstants() {
+ }
+}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
new file mode 100644
index 000000000000..b8381a7249be
--- /dev/null
+++ b/media/java/android/media/MediaController2.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
+import static android.media.MediaConstants.KEY_PACKAGE_NAME;
+import static android.media.MediaConstants.KEY_PID;
+import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Token.TYPE_SESSION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Allows an app to interact with an active {@link MediaSession2} or a
+ * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
+ * commands can be sent to the session.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * @hide
+ */
+public class MediaController2 implements AutoCloseable {
+ static final String TAG = "MediaController2";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final ControllerCallback mCallback;
+
+ private final IBinder.DeathRecipient mDeathRecipient = () -> close();
+ private final Context mContext;
+ private final Session2Token mSessionToken;
+ private final Executor mCallbackExecutor;
+ private final Controller2Link mControllerStub;
+ private final Handler mResultHandler;
+
+ private final Object mLock = new Object();
+ //@GuardedBy("mLock")
+ private int mNextSeqNumber;
+ //@GuardedBy("mLock")
+ private Session2Link mSessionBinder;
+ //@GuardedBy("mLock")
+ private Session2CommandGroup mAllowedCommands;
+ //@GuardedBy("mLock")
+ private Session2Token mConnectedToken;
+ //@GuardedBy("mLock")
+ private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+ //@GuardedBy("mLock")
+ private ArraySet<Integer> mRequestedCommandSeqNumbers;
+
+ /**
+ * Create a {@link MediaController2} from the {@link Session2Token}.
+ * This connects to the session and may wake up the service if it's not available.
+ *
+ * @param context Context
+ * @param token token to connect to
+ */
+ public MediaController2(@NonNull Context context, @NonNull Session2Token token) {
+ this(context, token, context.getMainExecutor(), new ControllerCallback() {});
+ }
+
+ /**
+ * Create a {@link MediaController2} from the {@link Session2Token}.
+ * This connects to the session and may wake up the service if it's not available.
+ *
+ * @param context Context
+ * @param token token to connect to
+ * @param executor executor to run callbacks on.
+ * @param callback controller callback to receive changes in.
+ */
+ public MediaController2(@NonNull Context context, @NonNull Session2Token token,
+ @NonNull Executor executor, @NonNull ControllerCallback callback) {
+ if (context == null) {
+ throw new IllegalArgumentException("context shouldn't be null");
+ }
+ if (token == null) {
+ throw new IllegalArgumentException("token shouldn't be null");
+ }
+ mContext = context;
+ mSessionToken = token;
+ mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor;
+ mCallback = (callback == null) ? new ControllerCallback() {} : callback;
+ mControllerStub = new Controller2Link(this);
+ // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
+ mResultHandler = new Handler(context.getMainLooper());
+
+ mNextSeqNumber = 0;
+ mPendingCommands = new ArrayMap<>();
+ mRequestedCommandSeqNumbers = new ArraySet<>();
+
+ if (token.getType() == TYPE_SESSION) {
+ connectToSession();
+ } else {
+ // TODO: Handle connect to session service.
+ }
+ }
+
+ @Override
+ public void close() {
+ synchronized (mLock) {
+ if (mSessionBinder != null) {
+ try {
+ mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
+ mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
+ } catch (RuntimeException e) {
+ // No-op
+ }
+ }
+ mPendingCommands.clear();
+ mRequestedCommandSeqNumbers.clear();
+ mCallbackExecutor.execute(() -> {
+ mCallback.onDisconnected(MediaController2.this);
+ });
+ mSessionBinder = null;
+ }
+ }
+
+ /**
+ * Sends a session command to the session
+ * <p>
+ * @param command the session command
+ * @param args optional arguments
+ * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
+ * when its result is received.
+ */
+ public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
+ if (command == null) {
+ throw new IllegalArgumentException("command shouldn't be null");
+ }
+
+ ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ synchronized (mLock) {
+ mPendingCommands.remove(this);
+ }
+ mCallbackExecutor.execute(() -> {
+ mCallback.onCommandResult(MediaController2.this, this,
+ command, new Session2Command.Result(resultCode, resultData));
+ });
+ }
+ };
+
+ synchronized (mLock) {
+ if (mSessionBinder != null) {
+ int seq = getNextSeqNumber();
+ mPendingCommands.put(resultReceiver, seq);
+ try {
+ mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args,
+ resultReceiver);
+ } catch (RuntimeException e) {
+ mPendingCommands.remove(resultReceiver);
+ resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
+ }
+ }
+ }
+ return resultReceiver;
+ }
+
+ /**
+ * Cancels the session command previously sent.
+ *
+ * @param token the token which is returned from {@link #sendSessionCommand}.
+ */
+ public void cancelSessionCommand(@NonNull Object token) {
+ if (token == null) {
+ throw new IllegalArgumentException("token shouldn't be null");
+ }
+ synchronized (mLock) {
+ if (mSessionBinder == null) return;
+ Integer seq = mPendingCommands.remove(token);
+ if (seq != null) {
+ mSessionBinder.cancelSessionCommand(mControllerStub, seq);
+ }
+ }
+ }
+
+ // Called by Controller2Link.onConnected
+ void onConnected(int seq, Bundle connectionResult) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2_STUB);
+ Session2CommandGroup allowedCommands =
+ connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
+ if (DEBUG) {
+ Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
+ + ", allowedCommands=" + allowedCommands);
+ }
+ if (sessionBinder == null || allowedCommands == null) {
+ // Connection rejected.
+ close();
+ return;
+ }
+ synchronized (mLock) {
+ mSessionBinder = sessionBinder;
+ mAllowedCommands = allowedCommands;
+ // Implementation for the local binder is no-op,
+ // so can be used without worrying about deadlock.
+ sessionBinder.linkToDeath(mDeathRecipient, 0);
+ mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
+ mSessionToken.getPackageName(), sessionBinder);
+ }
+ mCallbackExecutor.execute(() -> {
+ mCallback.onConnected(MediaController2.this, allowedCommands);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Controller2Link.onDisconnected
+ void onDisconnected(int seq) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // close() will call mCallback.onDisconnected
+ close();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Controller2Link.onSessionCommand
+ void onSessionCommand(int seq, Session2Command command, Bundle args,
+ @Nullable ResultReceiver resultReceiver) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ mRequestedCommandSeqNumbers.add(seq);
+ }
+ mCallbackExecutor.execute(() -> {
+ boolean isCanceled;
+ synchronized (mLock) {
+ isCanceled = !mRequestedCommandSeqNumbers.remove(seq);
+ }
+ if (isCanceled) {
+ resultReceiver.send(RESULT_INFO_SKIPPED, null);
+ return;
+ }
+ Session2Command.Result result = mCallback.onSessionCommand(
+ MediaController2.this, command, args);
+ if (resultReceiver != null) {
+ if (result == null) {
+ throw new RuntimeException("onSessionCommand shouldn't return null");
+ } else {
+ resultReceiver.send(result.getResultCode(), result.getResultData());
+ }
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Controller2Link.onSessionCommand
+ void onCancelCommand(int seq) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ mRequestedCommandSeqNumbers.remove(seq);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private int getNextSeqNumber() {
+ synchronized (mLock) {
+ return mNextSeqNumber++;
+ }
+ }
+
+ private void connectToSession() {
+ Session2Link sessionBinder = mSessionToken.getSessionLink();
+ Bundle connectionRequest = new Bundle();
+ connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
+ connectionRequest.putInt(KEY_PID, Process.myPid());
+
+ try {
+ sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed to call connection request. Framework will retry"
+ + " automatically");
+ }
+ }
+
+ /**
+ * Interface for listening to change in activeness of the {@link MediaSession2}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+ public abstract static class ControllerCallback {
+ /**
+ * Called when the controller is successfully connected to the session. The controller
+ * becomes available afterwards.
+ *
+ * @param controller the controller for this event
+ * @param allowedCommands commands that's allowed by the session.
+ */
+ public void onConnected(@NonNull MediaController2 controller,
+ @NonNull Session2CommandGroup allowedCommands) {}
+
+ /**
+ * Called when the session refuses the controller or the controller is disconnected from
+ * the session. The controller becomes unavailable afterwards and the callback wouldn't
+ * be called.
+ * <p>
+ * It will be also called after the {@link #close()}, so you can put clean up code here.
+ * You don't need to call {@link #close()} after this.
+ *
+ * @param controller the controller for this event
+ */
+ public void onDisconnected(@NonNull MediaController2 controller) {}
+
+ /**
+ * Called when the connected session sent a session command.
+ *
+ * @param controller the controller for this event
+ * @param command the session command
+ * @param args optional arguments
+ * @return the result for the session command. A runtime exception will be thrown if null
+ * is returned.
+ */
+ @NonNull
+ public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
+ @NonNull Session2Command command, @Nullable Bundle args) {
+ return null;
+ }
+
+ /**
+ * Called when the command sent to the connected session is finished.
+ *
+ * @param controller the controller for this event
+ * @param token the token got from {@link MediaController2#sendSessionCommand}
+ * @param command the session command
+ * @param result the result of the session command
+ */
+ public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
+ @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+ }
+}
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index aa2a937956c5..c496cf75995e 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -33,28 +33,15 @@ import java.util.List;
import java.util.concurrent.Executor;
/**
- * A class with information on a single media item with the metadata information. Here are use
- * cases.
- * <ul>
- * <li>Specify media items to {@link SessionPlayer2} for playback.
- * <li>Share media items across the processes.
- * </ul>
- * <p>
- * Subclasses of the session player may only accept certain subclasses of the media items. Check
- * the player documentation that you're interested in.
- * <p>
- * When it's shared across the processes, we cannot guarantee that they contain the right values
- * because media items are application dependent especially for the metadata.
- * <p>
- * This object is thread safe.
+ * A class with information on a single media item with the metadata information.
* <p>
* This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link androidx.media2.MediaItem} for consistent behavior across all devices.
- * </p>
- * @hide
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * <p>
*/
-public class MediaItem2 implements Parcelable {
+public final class MediaItem2 implements Parcelable {
private static final String TAG = "MediaItem2";
// intentionally less than long.MAX_VALUE.
@@ -81,7 +68,6 @@ public class MediaItem2 implements Parcelable {
}
};
- // TODO: Use SessionPlayer2.UNKNOWN_TIME instead
private static final long UNKNOWN_TIME = -1;
private final long mStartPositionMs;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index d656fa359826..33b8c4202fdd 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.Build;
import android.os.IBinder;
import java.io.FileDescriptor;
@@ -681,12 +682,12 @@ public class MediaMetadataRetriever implements AutoCloseable {
* allocated internally.
*/
public native void release();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native void native_setup();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static native void native_init();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native final void native_finalize();
@Override
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0057875ec3f4..fb18c3b67480 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -25,8 +25,10 @@ import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
+import android.graphics.SurfaceTexture;
+import android.media.SubtitleController.Anchor;
+import android.media.SubtitleTrack.RenderingWidget;
import android.net.Uri;
-import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -35,30 +37,19 @@ import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.PowerManager;
+import android.os.Process;
import android.os.SystemProperties;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-import android.util.ArrayMap;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
-import android.graphics.SurfaceTexture;
-import android.media.AudioManager;
-import android.media.MediaDrm;
-import android.media.MediaFormat;
-import android.media.MediaTimeProvider;
-import android.media.PlaybackParams;
-import android.media.SubtitleController;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleData;
-import android.media.SubtitleTrack.RenderingWidget;
-import android.media.SyncParams;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -72,7 +63,6 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.Runnable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2105,9 +2095,11 @@ public class MediaPlayer extends PlayerBase
mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
mOnTimedTextListener = null;
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
+ synchronized (mTimeProviderLock) {
+ if (mTimeProvider != null) {
+ mTimeProvider.close();
+ mTimeProvider = null;
+ }
}
synchronized(this) {
mSubtitleDataListenerDisabled = false;
@@ -2147,9 +2139,11 @@ public class MediaPlayer extends PlayerBase
if (mSubtitleController != null) {
mSubtitleController.reset();
}
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
+ synchronized (mTimeProviderLock) {
+ if (mTimeProvider != null) {
+ mTimeProvider.close();
+ mTimeProvider = null;
+ }
}
stayAwake(false);
@@ -2790,12 +2784,17 @@ public class MediaPlayer extends PlayerBase
synchronized (mIndexTrackPairs) {
mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
}
- Handler h = mTimeProvider.mEventHandler;
- int what = TimeProvider.NOTIFY;
- int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
- Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
- Message m = h.obtainMessage(what, arg1, 0, trackData);
- h.sendMessage(m);
+ synchronized (mTimeProviderLock) {
+ if (mTimeProvider != null) {
+ Handler h = mTimeProvider.mEventHandler;
+ int what = TimeProvider.NOTIFY;
+ int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
+ Pair<SubtitleTrack, byte[]> trackData =
+ Pair.create(track, contents.getBytes());
+ Message m = h.obtainMessage(what, arg1, 0, trackData);
+ h.sendMessage(m);
+ }
+ }
return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
}
@@ -3020,12 +3019,17 @@ public class MediaPlayer extends PlayerBase
total += bytes;
}
}
- Handler h = mTimeProvider.mEventHandler;
- int what = TimeProvider.NOTIFY;
- int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
- Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
- Message m = h.obtainMessage(what, arg1, 0, trackData);
- h.sendMessage(m);
+ synchronized (mTimeProviderLock) {
+ if (mTimeProvider != null) {
+ Handler h = mTimeProvider.mEventHandler;
+ int what = TimeProvider.NOTIFY;
+ int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
+ Pair<SubtitleTrack, byte[]> trackData =
+ Pair.create(track, bos.toByteArray());
+ Message m = h.obtainMessage(what, arg1, 0, trackData);
+ h.sendMessage(m);
+ }
+ }
return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
@@ -3308,14 +3312,17 @@ public class MediaPlayer extends PlayerBase
private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private TimeProvider mTimeProvider;
+ private final Object mTimeProviderLock = new Object();
/** @hide */
@UnsupportedAppUsage
public MediaTimeProvider getMediaTimeProvider() {
- if (mTimeProvider == null) {
- mTimeProvider = new TimeProvider(this);
+ synchronized (mTimeProviderLock) {
+ if (mTimeProvider == null) {
+ mTimeProvider = new TimeProvider(this);
+ }
+ return mTimeProvider;
}
- return mTimeProvider;
}
private class EventHandler extends Handler
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 125ab2e91e22..b16002900799 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.hardware.Camera;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -105,12 +106,12 @@ public class MediaRecorder implements AudioRouting,
@UnsupportedAppUsage
private Surface mSurface;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mPath;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private FileDescriptor mFd;
private File mFile;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private EventHandler mEventHandler;
@UnsupportedAppUsage
private OnErrorListener mOnErrorListener;
@@ -958,7 +959,7 @@ public class MediaRecorder implements AudioRouting,
// native implementation
private native void _setOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
private native void _setNextOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native void _prepare() throws IllegalStateException, IOException;
/**
@@ -1060,7 +1061,7 @@ public class MediaRecorder implements AudioRouting,
mEventHandler.removeCallbacksAndMessages(null);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native void native_reset();
/**
@@ -1569,14 +1570,14 @@ public class MediaRecorder implements AudioRouting,
*/
public native void release();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static native final void native_init();
@UnsupportedAppUsage
private native final void native_setup(Object mediarecorder_this,
String clientName, String opPackageName) throws IllegalStateException;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private native final void native_finalize();
@UnsupportedAppUsage
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 90cfc534877e..4eed12f428bc 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -902,6 +902,7 @@ public class MediaScanner implements AutoCloseable {
map.put(MediaStore.MediaColumns.SIZE, mFileSize);
map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm);
+ map.putNull(MediaStore.MediaColumns.HASH);
String resolution = null;
if (mWidth > 0 && mHeight > 0) {
@@ -934,7 +935,7 @@ public class MediaScanner implements AutoCloseable {
}
} else if (MediaFile.isImageMimeType(mMimeType)) {
// FIXME - add DESCRIPTION
- } else if (mScanSuccess && MediaFile.isAudioMimeType(mMimeType)) {
+ } else if (MediaFile.isAudioMimeType(mMimeType)) {
map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
mArtist : MediaStore.UNKNOWN_STRING);
map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
@@ -950,10 +951,6 @@ public class MediaScanner implements AutoCloseable {
map.put(Audio.Media.DURATION, mDuration);
map.put(Audio.Media.COMPILATION, mCompilation);
}
- if (!mScanSuccess) {
- // force mediaprovider to not determine the media type from the mime type
- map.put(Files.FileColumns.MEDIA_TYPE, 0);
- }
}
return map;
}
@@ -1056,7 +1053,7 @@ public class MediaScanner implements AutoCloseable {
Uri tableUri = mFilesUri;
int mediaType = FileColumns.MEDIA_TYPE_NONE;
MediaInserter inserter = mMediaInserter;
- if (mScanSuccess && !mNoMedia) {
+ if (!mNoMedia) {
if (MediaFile.isVideoMimeType(mMimeType)) {
tableUri = mVideoUri;
mediaType = FileColumns.MEDIA_TYPE_VIDEO;
@@ -1131,7 +1128,7 @@ public class MediaScanner implements AutoCloseable {
// with squashed lower case paths
values.remove(MediaStore.MediaColumns.DATA);
- if (mScanSuccess && !mNoMedia) {
+ if (!mNoMedia) {
// Changing media type must be done as separate update
if (mediaType != entry.mMediaType) {
final ContentValues mediaTypeValues = new ContentValues();
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
new file mode 100644
index 000000000000..1ee851f5a068
--- /dev/null
+++ b/media/java/android/media/MediaSession2.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
+import static android.media.MediaConstants.KEY_PACKAGE_NAME;
+import static android.media.MediaConstants.KEY_PID;
+import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Token.TYPE_SESSION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Allows a media app to expose its transport controls and playback information in a process to
+ * other processes including the Android framework and other apps.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * @hide
+ */
+public class MediaSession2 implements AutoCloseable {
+ static final String TAG = "MediaSession";
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // Note: This checks the uniqueness of a session ID only in a single process.
+ // When the framework becomes able to check the uniqueness, this logic should be removed.
+ //@GuardedBy("MediaSession.class")
+ private static final List<String> SESSION_ID_LIST = new ArrayList<>();
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Object mLock = new Object();
+ //@GuardedBy("mLock")
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Map<Controller2Link, ControllerInfo> mConnectedControllers = new HashMap<>();
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Context mContext;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Executor mCallbackExecutor;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final SessionCallback mCallback;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Session2Link mSessionStub;
+
+ private final String mSessionId;
+ private final PendingIntent mSessionActivity;
+ private final Session2Token mSessionToken;
+ private final MediaSessionManager mSessionManager;
+ private final Handler mResultHandler;
+
+ //@GuardedBy("mLock")
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ private boolean mClosed;
+
+ MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
+ @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
+ synchronized (MediaSession2.class) {
+ if (SESSION_ID_LIST.contains(id)) {
+ throw new IllegalStateException("Session ID must be unique. ID=" + id);
+ }
+ SESSION_ID_LIST.add(id);
+ }
+
+ mContext = context;
+ mSessionId = id;
+ mSessionActivity = sessionActivity;
+ mCallbackExecutor = callbackExecutor;
+ mCallback = callback;
+ mSessionStub = new Session2Link(this);
+ mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
+ mSessionStub);
+ mSessionManager = (MediaSessionManager) mContext.getSystemService(
+ Context.MEDIA_SESSION_SERVICE);
+ // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
+ mResultHandler = new Handler(context.getMainLooper());
+ }
+
+ @Override
+ public void close() {
+ try {
+ synchronized (MediaSession2.class) {
+ SESSION_ID_LIST.remove(mSessionId);
+ }
+ Collection<ControllerInfo> controllerInfos;
+ synchronized (mLock) {
+ controllerInfos = mConnectedControllers.values();
+ mConnectedControllers.clear();
+ mClosed = true;
+ }
+ for (ControllerInfo info : controllerInfos) {
+ info.notifyDisconnected();
+ }
+ } catch (Exception e) {
+ // Should not be here.
+ }
+ }
+
+ /**
+ * Returns the session ID
+ */
+ @NonNull
+ public String getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * Returns the {@link Session2Token} for creating {@link MediaController2}.
+ */
+ @NonNull
+ public Session2Token getSessionToken() {
+ return mSessionToken;
+ }
+
+ /**
+ * Broadcasts a session command to all the connected controllers
+ * <p>
+ * @param command the session command
+ * @param args optional arguments
+ */
+ public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
+ if (command == null) {
+ throw new IllegalArgumentException("command shouldn't be null");
+ }
+ Collection<ControllerInfo> controllerInfos;
+ synchronized (mLock) {
+ controllerInfos = mConnectedControllers.values();
+ }
+ for (ControllerInfo controller : controllerInfos) {
+ controller.sendSessionCommand(command, args, null);
+ }
+ }
+
+ /**
+ * Sends a session command to a specific controller
+ * <p>
+ * @param controller the controller to get the session command
+ * @param command the session command
+ * @param args optional arguments
+ * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
+ * when its result is received.
+ */
+ public Object sendSessionCommand(@NonNull ControllerInfo controller,
+ @NonNull Session2Command command, @Nullable Bundle args) {
+ if (controller == null) {
+ throw new IllegalArgumentException("controller shouldn't be null");
+ }
+ if (command == null) {
+ throw new IllegalArgumentException("command shouldn't be null");
+ }
+ ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ controller.receiveCommandResult(this);
+ mCallbackExecutor.execute(() -> {
+ mCallback.onCommandResult(MediaSession2.this, controller, this,
+ command, new Session2Command.Result(resultCode, resultData));
+ });
+ }
+ };
+ controller.sendSessionCommand(command, args, resultReceiver);
+ return resultReceiver;
+ }
+
+ /**
+ * Cancels the session command previously sent.
+ *
+ * @param controller the controller to get the session command
+ * @param token the token which is returned from {@link #sendSessionCommand}.
+ */
+ public void cancelSessionCommand(ControllerInfo controller, Object token) {
+ if (token == null) {
+ throw new IllegalArgumentException("token shouldn't be null");
+ }
+ controller.cancelSessionCommand(token);
+ }
+
+ boolean isClosed() {
+ synchronized (mLock) {
+ return mClosed;
+ }
+ }
+
+ // Called by Session2Link.onConnect
+ void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) {
+ if (controller == null || connectionRequest == null) {
+ return;
+ }
+ final int uid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final long token = Binder.clearCallingIdentity();
+ // Binder.getCallingPid() can be 0 for an oneway call from the remote process.
+ // If it's the case, use PID from the ConnectionRequest.
+ final int pid = (callingPid != 0) ? callingPid : connectionRequest.getInt(KEY_PID);
+ final String pkg = connectionRequest.getString(KEY_PACKAGE_NAME);
+ try {
+ RemoteUserInfo remoteUserInfo = new RemoteUserInfo(pkg, pid, uid);
+ final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
+ mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
+ mCallbackExecutor.execute(() -> {
+ if (isClosed()) {
+ return;
+ }
+ controllerInfo.mAllowedCommands =
+ mCallback.onConnect(MediaSession2.this, controllerInfo);
+ // Don't reject connection for the request from trusted app.
+ // Otherwise server will fail to retrieve session's information to dispatch
+ // media keys to.
+ boolean accept =
+ controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
+ if (accept) {
+ if (controllerInfo.mAllowedCommands == null) {
+ // For trusted apps, send non-null allowed commands to keep
+ // connection.
+ controllerInfo.mAllowedCommands = new Session2CommandGroup();
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Accepting connection: " + controllerInfo);
+ }
+ synchronized (mLock) {
+ if (mConnectedControllers.containsKey(controller)) {
+ Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
+ + " request multiple times");
+ }
+ mConnectedControllers.put(controller, controllerInfo);
+ }
+ // If connection is accepted, notify the current state to the controller.
+ // It's needed because we cannot call synchronous calls between
+ // session/controller.
+ Bundle connectionResult = new Bundle();
+ connectionResult.putParcelable(KEY_SESSION2_STUB, mSessionStub);
+ connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
+ controllerInfo.mAllowedCommands);
+
+ // Double check if session is still there, because close() can be called in
+ // another thread.
+ if (isClosed()) {
+ return;
+ }
+ controllerInfo.notifyConnected(connectionResult);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
+ }
+ controllerInfo.notifyDisconnected();
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Session2Link.onDisconnect
+ void onDisconnect(final Controller2Link controller, int seq) {
+ if (controller == null) {
+ return;
+ }
+ final ControllerInfo controllerInfo;
+ synchronized (mLock) {
+ controllerInfo = mConnectedControllers.get(controller);
+ }
+ if (controllerInfo == null) {
+ return;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallbackExecutor.execute(() -> {
+ mCallback.onDisconnected(MediaSession2.this, controllerInfo);
+ });
+ mConnectedControllers.remove(controller);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Session2Link.onSessionCommand
+ void onSessionCommand(final Controller2Link controller, final int seq,
+ final Session2Command command, final Bundle args,
+ @Nullable ResultReceiver resultReceiver) {
+ if (controller == null) {
+ return;
+ }
+ final ControllerInfo controllerInfo;
+ synchronized (mLock) {
+ controllerInfo = mConnectedControllers.get(controller);
+ }
+ if (controllerInfo == null) {
+ return;
+ }
+
+ // TODO: check allowed commands.
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ controllerInfo.addRequestedCommandSeqNumber(seq);
+ }
+
+ mCallbackExecutor.execute(() -> {
+ if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
+ resultReceiver.send(RESULT_INFO_SKIPPED, null);
+ return;
+ }
+ Session2Command.Result result = mCallback.onSessionCommand(
+ MediaSession2.this, controllerInfo, command, args);
+ if (resultReceiver != null) {
+ if (result == null) {
+ throw new RuntimeException("onSessionCommand shouldn't return null");
+ } else {
+ resultReceiver.send(result.getResultCode(), result.getResultData());
+ }
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Called by Session2Link.onCancelCommand
+ void onCancelCommand(final Controller2Link controller, final int seq) {
+ final ControllerInfo controllerInfo;
+ synchronized (mLock) {
+ controllerInfo = mConnectedControllers.get(controller);
+ }
+ if (controllerInfo == null) {
+ return;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ controllerInfo.removeRequestedCommandSeqNumber(seq);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Builder for {@link MediaSession2}.
+ * <p>
+ * Any incoming event from the {@link MediaController2} will be handled on the callback
+ * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
+ */
+ public static final class Builder {
+ private Context mContext;
+ private String mId;
+ private PendingIntent mSessionActivity;
+ private Executor mCallbackExecutor;
+ private SessionCallback mCallback;
+
+ /**
+ * Creates a builder for {@link MediaSession2}.
+ *
+ * @param context Context
+ * @throws IllegalArgumentException if context is {@code null}.
+ */
+ public Builder(@NonNull Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("context shouldn't be null");
+ }
+ mContext = context;
+ }
+
+ /**
+ * Set an intent for launching UI for this Session. This can be used as a
+ * quick link to an ongoing media screen. The intent should be for an
+ * activity that may be started using {@link Context#startActivity(Intent)}.
+ *
+ * @param pi The intent to launch to show UI for this session.
+ * @return The Builder to allow chaining
+ */
+ @NonNull
+ public Builder setSessionActivity(@Nullable PendingIntent pi) {
+ mSessionActivity = pi;
+ return this;
+ }
+
+ /**
+ * Set ID of the session. If it's not set, an empty string will be used to create a session.
+ * <p>
+ * Use this if and only if your app supports multiple playback at the same time and also
+ * wants to provide external apps to have finer controls of them.
+ *
+ * @param id id of the session. Must be unique per package.
+ * @throws IllegalArgumentException if id is {@code null}.
+ * @return The Builder to allow chaining
+ */
+ @NonNull
+ public Builder setId(@NonNull String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("id shouldn't be null");
+ }
+ mId = id;
+ return this;
+ }
+
+ /**
+ * Set callback for the session and its executor.
+ *
+ * @param executor callback executor
+ * @param callback session callback.
+ * @return The Builder to allow chaining
+ */
+ @NonNull
+ public Builder setSessionCallback(@NonNull Executor executor,
+ @NonNull SessionCallback callback) {
+ mCallbackExecutor = executor;
+ mCallback = callback;
+ return this;
+ }
+
+ /**
+ * Build {@link MediaSession2}.
+ *
+ * @return a new session
+ * @throws IllegalStateException if the session with the same id is already exists for the
+ * package.
+ */
+ @NonNull
+ public MediaSession2 build() {
+ if (mCallbackExecutor == null) {
+ mCallbackExecutor = mContext.getMainExecutor();
+ }
+ if (mCallback == null) {
+ mCallback = new SessionCallback() {};
+ }
+ if (mId == null) {
+ mId = "";
+ }
+ MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
+ mCallbackExecutor, mCallback);
+
+ // Notify framework about the newly create session after the constructor is finished.
+ // Otherwise, framework may access the session before the initialization is finished.
+ try {
+ MediaSessionManager manager = (MediaSessionManager) mContext.getSystemService(
+ Context.MEDIA_SESSION_SERVICE);
+ manager.notifySession2Created(session2.getSessionToken());
+ } catch (Exception e) {
+ session2.close();
+ throw e;
+ }
+
+ return session2;
+ }
+ }
+
+ /**
+ * Information of a controller.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+ public static final class ControllerInfo {
+ private final RemoteUserInfo mRemoteUserInfo;
+ private final boolean mIsTrusted;
+ private final Controller2Link mControllerBinder;
+ private final Object mLock = new Object();
+ //@GuardedBy("mLock")
+ private int mNextSeqNumber;
+ //@GuardedBy("mLock")
+ private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+ //@GuardedBy("mLock")
+ private ArraySet<Integer> mRequestedCommandSeqNumbers;
+
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ Session2CommandGroup mAllowedCommands;
+
+ /**
+ * @param remoteUserInfo remote user info
+ * @param trusted {@code true} if trusted, {@code false} otherwise
+ * @param controllerBinder Controller2Link for the connected controller.
+ */
+ ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
+ @Nullable Controller2Link controllerBinder) {
+ mRemoteUserInfo = remoteUserInfo;
+ mIsTrusted = trusted;
+ mControllerBinder = controllerBinder;
+ mPendingCommands = new ArrayMap<>();
+ mRequestedCommandSeqNumbers = new ArraySet<>();
+ }
+
+ /**
+ * @return remote user info of the controller.
+ */
+ @NonNull
+ public RemoteUserInfo getRemoteUserInfo() {
+ return mRemoteUserInfo;
+ }
+
+ /**
+ * @return package name of the controller.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mRemoteUserInfo.getPackageName();
+ }
+
+ /**
+ * @return uid of the controller. Can be a negative value if the uid cannot be obtained.
+ */
+ public int getUid() {
+ return mRemoteUserInfo.getUid();
+ }
+
+ /**
+ * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or
+ * has a enabled notification listener so can be trusted to accept connection and incoming
+ * command request.
+ *
+ * @return {@code true} if the controller is trusted.
+ * @hide
+ */
+ public boolean isTrusted() {
+ return mIsTrusted;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mControllerBinder, mRemoteUserInfo);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ControllerInfo)) return false;
+ if (this == obj) return true;
+
+ ControllerInfo other = (ControllerInfo) obj;
+ if (mControllerBinder != null || other.mControllerBinder != null) {
+ return Objects.equals(mControllerBinder, other.mControllerBinder);
+ }
+ return mRemoteUserInfo.equals(other.mRemoteUserInfo);
+ }
+
+ @Override
+ public String toString() {
+ return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
+ + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
+ }
+
+ void notifyConnected(Bundle connectionResult) {
+ if (mControllerBinder == null) return;
+
+ try {
+ mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult);
+ } catch (RuntimeException e) {
+ // Controller may be died prematurely.
+ }
+ }
+
+ void notifyDisconnected() {
+ if (mControllerBinder == null) return;
+
+ try {
+ mControllerBinder.notifyDisconnected(getNextSeqNumber());
+ } catch (RuntimeException e) {
+ // Controller may be died prematurely.
+ }
+ }
+
+ void sendSessionCommand(Session2Command command, Bundle args,
+ ResultReceiver resultReceiver) {
+ if (mControllerBinder == null) return;
+
+ try {
+ int seq = getNextSeqNumber();
+ synchronized (mLock) {
+ mPendingCommands.put(resultReceiver, seq);
+ }
+ mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
+ } catch (RuntimeException e) {
+ // Controller may be died prematurely.
+ synchronized (mLock) {
+ mPendingCommands.remove(resultReceiver);
+ }
+ resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
+ }
+ }
+
+ void cancelSessionCommand(@NonNull Object token) {
+ if (mControllerBinder == null) return;
+ Integer seq;
+ synchronized (mLock) {
+ seq = mPendingCommands.remove(token);
+ }
+ if (seq != null) {
+ mControllerBinder.cancelSessionCommand(seq);
+ }
+ }
+
+ void receiveCommandResult(ResultReceiver resultReceiver) {
+ synchronized (mLock) {
+ mPendingCommands.remove(resultReceiver);
+ }
+ }
+
+ void addRequestedCommandSeqNumber(int seq) {
+ synchronized (mLock) {
+ mRequestedCommandSeqNumbers.add(seq);
+ }
+ }
+
+ boolean removeRequestedCommandSeqNumber(int seq) {
+ synchronized (mLock) {
+ return mRequestedCommandSeqNumbers.remove(seq);
+ }
+ }
+
+ private int getNextSeqNumber() {
+ synchronized (mLock) {
+ return mNextSeqNumber++;
+ }
+ }
+ }
+
+ /**
+ * Callback to be called for all incoming commands from {@link MediaController2}s.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ */
+ public abstract static class SessionCallback {
+ /**
+ * Called when a controller is created for this session. Return allowed commands for
+ * controller. By default it returns {@code null}.
+ * <p>
+ * You can reject the connection by returning {@code null}. In that case, controller
+ * receives {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)}
+ * and cannot be used.
+ *
+ * @param session the session for this event
+ * @param controller controller information.
+ * @return allowed commands. Can be {@code null} to reject connection.
+ */
+ @Nullable
+ public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller) {
+ return null;
+ }
+
+ /**
+ * Called when a controller is disconnected
+ *
+ * @param session the session for this event
+ * @param controller controller information
+ */
+ public void onDisconnected(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller) {}
+
+ /**
+ * Called when a controller sent a session command.
+ *
+ * @param session the session for this event
+ * @param controller controller information
+ * @param command the session command
+ * @param args optional arguments
+ * @return the result for the session command. A runtime exception will be thrown if null
+ * is returned.
+ */
+ @NonNull
+ public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Session2Command command,
+ @Nullable Bundle args) {
+ return null;
+ }
+
+ /**
+ * Called when the command sent to the controller is finished.
+ *
+ * @param session the session for this event
+ * @param controller controller information
+ * @param token the token got from {@link MediaSession2#sendSessionCommand}
+ * @param command the session command
+ * @param result the result of the session command
+ */
+ public void onCommandResult(@NonNull MediaSession2 session,
+ @NonNull ControllerInfo controller, @NonNull Object token,
+ @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+ }
+}
diff --git a/media/java/android/media/Session2Command.aidl b/media/java/android/media/Session2Command.aidl
new file mode 100644
index 000000000000..43a7b123ed29
--- /dev/null
+++ b/media/java/android/media/Session2Command.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable Session2Command;
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
index a5e2ae4488a9..d2a5aae435a1 100644
--- a/media/java/android/media/Session2Command.java
+++ b/media/java/android/media/Session2Command.java
@@ -16,18 +16,13 @@
package android.media;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.util.ArrayMap;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
import java.util.Objects;
/**
@@ -46,368 +41,26 @@ import java.util.Objects;
*/
public final class Session2Command implements Parcelable {
/**
- * The first version of session commands. This version is for commands introduced in API 29.
- * <p>
- * This would be used to specify which commands should be added by
- * {@link Session2CommandGroup.Builder#addAllPredefinedCommands(int)}
- *
- * @see Session2CommandGroup.Builder#addAllPredefinedCommands(int)
- */
- public static final int COMMAND_VERSION_1 = 1;
-
- /**
- * @hide
- */
- public static final int COMMAND_VERSION_CURRENT = COMMAND_VERSION_1;
-
- /**
- * @hide
- */
- @IntDef({COMMAND_VERSION_1})
- @Retention(RetentionPolicy.SOURCE)
- public @interface CommandVersion {}
-
- /**
- * @hide
- */
- @IntDef({COMMAND_CODE_CUSTOM,
- COMMAND_CODE_PLAYER_PLAY,
- COMMAND_CODE_PLAYER_PAUSE,
- COMMAND_CODE_PLAYER_PREPARE,
- COMMAND_CODE_PLAYER_SEEK_TO,
- COMMAND_CODE_PLAYER_SET_SPEED,
- COMMAND_CODE_PLAYER_GET_PLAYLIST,
- COMMAND_CODE_PLAYER_SET_PLAYLIST,
- COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE,
- COMMAND_CODE_PLAYER_SET_REPEAT_MODE,
- COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA,
- COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM,
- COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM,
- COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA,
- COMMAND_CODE_PLAYER_SET_MEDIA_ITEM,
- COMMAND_CODE_VOLUME_SET_VOLUME,
- COMMAND_CODE_VOLUME_ADJUST_VOLUME,
- COMMAND_CODE_SESSION_FAST_FORWARD,
- COMMAND_CODE_SESSION_REWIND,
- COMMAND_CODE_SESSION_SKIP_FORWARD,
- COMMAND_CODE_SESSION_SKIP_BACKWARD,
- COMMAND_CODE_SESSION_SET_RATING,
- COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
- COMMAND_CODE_LIBRARY_SUBSCRIBE,
- COMMAND_CODE_LIBRARY_UNSUBSCRIBE,
- COMMAND_CODE_LIBRARY_GET_CHILDREN,
- COMMAND_CODE_LIBRARY_GET_ITEM,
- COMMAND_CODE_LIBRARY_SEARCH,
- COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CommandCode {}
-
- /**
* Command code for the custom command which can be defined by string action in the
* {@link Session2Command}.
*/
public static final int COMMAND_CODE_CUSTOM = 0;
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Player commands (i.e. commands to {@link Session2Player})
- ////////////////////////////////////////////////////////////////////////////////////////////////
- static final ArrayMap<Integer, Range> VERSION_PLAYER_COMMANDS_MAP = new ArrayMap<>();
- static final ArrayMap<Integer, Range> VERSION_PLAYER_PLAYLIST_COMMANDS_MAP = new ArrayMap<>();
-
- // TODO: check the link tag, and reassign int values properly.
- /**
- * Command code for {@link MediaController2#play()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
- * Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_PLAY = 10000;
-
- /**
- * Command code for {@link MediaController2#pause()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
- * Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_PAUSE = 10001;
-
- /**
- * Command code for {@link MediaController2#prepare()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
- * Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_PREPARE = 10002;
-
- /**
- * Command code for {@link MediaController2#seekTo(long)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
- * Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SEEK_TO = 10003;
-
- /**
- * Command code for {@link MediaController2#setPlaybackSpeed(float)}}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session22Callback#onCommandRequest(MediaSession2, Controller2Info,
- * Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SET_SPEED = 10004;
-
- /**
- * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
- * information to the controller.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST = 10005;
-
- /**
- * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SET_PLAYLIST = 10006;
-
- /**
- * Command code for {@link MediaController2#skipToPlaylistItem(int)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM = 10007;
-
- /**
- * Command code for {@link MediaController2#skipToPreviousPlaylistItem()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(
- * MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM = 10008;
-
- /**
- * Command code for {@link MediaController2#skipToNextPlaylistItem()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link Session2Callback#onCommandRequest(
- * MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
-
- public static final int COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM = 10009;
-
- /**
- * Command code for {@link MediaController2#setShuffleMode(int)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE = 10010;
-
- /**
- * Command code for {@link MediaController2#setRepeatMode(int)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_SET_REPEAT_MODE = 10011;
-
- /**
- * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose metadata
- * information to the controller.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA = 10012;
-
- /**
- * Command code for {@link MediaController2#addPlaylistItem(int, String)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM = 10013;
-
- /**
- * Command code for {@link MediaController2#removePlaylistItem(int, String)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM = 10014;
-
- /**
- * Command code for {@link MediaController2#replacePlaylistItem(int, String)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM = 10015;
-
/**
- * Command code for {@link MediaController2#getCurrentMediaItem()}. This will expose metadata
- * information to the controller.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
+ * Result code representing that the command is skipped or canceled. For an example, a seek
+ * command can be skipped if it is followed by another seek command.
*/
- public static final int COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM = 10016;
+ public static final int RESULT_INFO_SKIPPED = 1;
/**
- * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
+ * Result code representing that the command is successfully completed.
*/
- public static final int COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA = 10017;
+ public static final int RESULT_SUCCESS = 0;
/**
- * Command code for {@link MediaController2#setMediaItem(String)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
+ * Result code represents that call is ended with an unknown error.
*/
- public static final int COMMAND_CODE_PLAYER_SET_MEDIA_ITEM = 10018;
-
- static {
- VERSION_PLAYER_COMMANDS_MAP.put(COMMAND_VERSION_1,
- new Range(COMMAND_CODE_PLAYER_PLAY, COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
- }
-
- static {
- VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.put(COMMAND_VERSION_1,
- new Range(COMMAND_CODE_PLAYER_GET_PLAYLIST,
- COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Volume commands (i.e. commands to {@link AudioManager} or {@link RouteMediaPlayer})
- ////////////////////////////////////////////////////////////////////////////////////////////////
- static final ArrayMap<Integer, Range> VERSION_VOLUME_COMMANDS_MAP = new ArrayMap<>();
-
- /**
- * Command code for {@link MediaController2#setVolumeTo(int, int)}.
- * <p>
- * <p>
- * If the session doesn't reject the request through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
- * command would adjust the device volume. It would send to the player directly only if it's
- * remote player. See RouteMediaPlayer for a remote player.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_VOLUME_SET_VOLUME = 30000;
-
- /**
- * Command code for {@link MediaController2#adjustVolume(int, int)}.
- * <p>
- * If the session doesn't reject the request through the
- * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
- * command would adjust the device volume. It would send to the player directly only if it's
- * remote player. See RouteMediaPlayer for a remote player.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_VOLUME_ADJUST_VOLUME = 30001;
-
- static {
- VERSION_VOLUME_COMMANDS_MAP.put(COMMAND_VERSION_1,
- new Range(COMMAND_CODE_VOLUME_SET_VOLUME,
- COMMAND_CODE_VOLUME_ADJUST_VOLUME));
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Session commands (i.e. commands to {@link MediaSession2#Session2Callback})
- ////////////////////////////////////////////////////////////////////////////////////////////////
- static final ArrayMap<Integer, Range> VERSION_SESSION_COMMANDS_MAP = new ArrayMap<>();
-
- /**
- * Command code for {@link MediaController2#fastForward()}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 40000;
-
- /**
- * Command code for {@link MediaController2#rewind()}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_SESSION_REWIND = 40001;
-
- /**
- * Command code for {@link MediaController2#skipForward()}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_SESSION_SKIP_FORWARD = 40002;
-
- /**
- * Command code for {@link MediaController2#skipBackward()}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_SESSION_SKIP_BACKWARD = 40003;
-
- /**
- * Command code for {@link MediaController2#setRating(String, Rating)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_SESSION_SET_RATING = 40010;
+ public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
public static final Parcelable.Creator<Session2Command> CREATOR =
new Parcelable.Creator<Session2Command>() {
@@ -422,82 +75,17 @@ public final class Session2Command implements Parcelable {
}
};
- static {
- VERSION_SESSION_COMMANDS_MAP.put(COMMAND_VERSION_1,
- new Range(COMMAND_CODE_SESSION_FAST_FORWARD, COMMAND_CODE_SESSION_SET_RATING));
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Session commands (i.e. commands to {@link MediaLibrarySession#MediaLibrarySessionCallback})
- ////////////////////////////////////////////////////////////////////////////////////////////////
- static final ArrayMap<Integer, Range> VERSION_LIBRARY_COMMANDS_MAP = new ArrayMap<>();
-
- /**
- * Command code for {@link MediaBrowser2#getLibraryRoot(Library2Params)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 50000;
-
- /**
- * Command code for {@link MediaBrowser2#subscribe(String, Library2Params)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 50001;
-
- /**
- * Command code for {@link MediaBrowser2#unsubscribe(String)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 50002;
-
- /**
- * Command code for {@link MediaBrowser2#getChildren(String, int, int, Library2Params)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 50003;
-
- /**
- * Command code for {@link MediaBrowser2#getItem(String)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 50004;
-
- /**
- * Command code for {@link MediaBrowser2#search(String, LibraryParams)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_SEARCH = 50005;
-
- /**
- * Command code for {@link MediaBrowser2#getSearchResult(String, int, int, Library2Params)}.
- * <p>
- * Code version is {@link #COMMAND_VERSION_1}.
- */
- public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 50006;
-
- static {
- VERSION_LIBRARY_COMMANDS_MAP.put(COMMAND_VERSION_1,
- new Range(COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
- COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT));
- }
-
- @CommandCode private final int mCommandCode;
+ private final int mCommandCode;
// Nonnull if it's custom command
private final String mCustomCommand;
private final Bundle mExtras;
/**
- * Constructor for creating a predefined command.
+ * Constructor for creating a command predefined in AndroidX media2.
*
- * @param commandCode A command code for predefined command.
+ * @param commandCode A command code for a command predefined in AndroidX media2.
*/
- public Session2Command(@CommandCode int commandCode) {
+ public Session2Command(int commandCode) {
if (commandCode == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
}
@@ -535,7 +123,7 @@ public final class Session2Command implements Parcelable {
* Gets the command code of a predefined command.
* This will return {@link #COMMAND_CODE_CUSTOM} for a custom command.
*/
- public @CommandCode int getCommandCode() {
+ public int getCommandCode() {
return mCommandCode;
}
@@ -543,7 +131,8 @@ public final class Session2Command implements Parcelable {
* Gets the action of a custom command.
* This will return {@code null} for a predefined command.
*/
- public @Nullable String getCustomCommand() {
+ @Nullable
+ public String getCustomCommand() {
return mCustomCommand;
}
@@ -551,7 +140,8 @@ public final class Session2Command implements Parcelable {
* Gets the extra bundle of a custom command.
* This will return {@code null} for a predefined command.
*/
- public @Nullable Bundle getExtras() {
+ @Nullable
+ public Bundle getExtras() {
return mExtras;
}
@@ -582,15 +172,36 @@ public final class Session2Command implements Parcelable {
return Objects.hash(mCustomCommand, mCommandCode);
}
- @SuppressWarnings("WeakerAccess") /* synthetic access */
- static final class Range {
- public final int lower;
- public final int upper;
+ /**
+ * Contains the result of {@link Session2Command}.
+ */
+ public static final class Result {
+ private final int mResultCode;
+ private final Bundle mResultData;
+
+ /**
+ * Constructor of {@link Result}.
+ *
+ * @param resultCode result code
+ * @param resultData result data
+ */
+ public Result(int resultCode, Bundle resultData) {
+ mResultCode = resultCode;
+ mResultData = resultData;
+ }
- Range(int lower, int upper) {
- this.lower = lower;
- this.upper = upper;
+ /**
+ * Returns the result code.
+ */
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ /**
+ * Returns the result data.
+ */
+ public Bundle getResultData() {
+ return mResultData;
}
}
}
-
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
index de34fe5c8a2a..122dfb156567 100644
--- a/media/java/android/media/Session2CommandGroup.java
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -17,14 +17,11 @@
package android.media;
import static android.media.Session2Command.COMMAND_CODE_CUSTOM;
-import static android.media.Session2Command.COMMAND_VERSION_1;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.media.Session2Command.Range;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArrayMap;
import java.util.Collection;
import java.util.HashSet;
@@ -34,8 +31,9 @@ import java.util.Set;
* A set of {@link Session2Command} which represents a command group.
* <p>
* This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
- * {@link androidx.media2.SessionCommandGroup} for consistent behavior across all devices.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
* </p>
* @hide
*/
@@ -60,7 +58,7 @@ public final class Session2CommandGroup implements Parcelable {
/**
* Default Constructor.
*/
- public Session2CommandGroup() { }
+ public Session2CommandGroup() {}
/**
* Creates a new Session2CommandGroup with commands copied from another object.
@@ -88,38 +86,6 @@ public final class Session2CommandGroup implements Parcelable {
}
/**
- * Adds a command to this command group.
- *
- * @param command A command to add. Shouldn't be {@code null}.
- * @hide TODO remove this method
- */
- public void addCommand(@NonNull Session2Command command) {
- if (command == null) {
- throw new IllegalArgumentException("command shouldn't be null");
- }
- if (!hasCommand(command)) {
- mCommands.add(command);
- }
- }
-
- /**
- * Adds a predefined command with given {@code commandCode} to this command group.
- *
- * @param commandCode A command code to add.
- * Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
- * @hide TODO remove this method
- */
- public void addCommand(@Session2Command.CommandCode int commandCode) {
- if (commandCode == COMMAND_CODE_CUSTOM) {
- throw new IllegalArgumentException(
- "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
- }
- if (!hasCommand(commandCode)) {
- mCommands.add(new Session2Command(commandCode));
- }
- }
-
- /**
* Checks whether this command group has a command that matches given {@code command}.
*
* @param command A command to find. Shouldn't be {@code null}.
@@ -137,7 +103,7 @@ public final class Session2CommandGroup implements Parcelable {
* @param commandCode A command code to find.
* Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
*/
- public boolean hasCommand(@Session2Command.CommandCode int commandCode) {
+ public boolean hasCommand(int commandCode) {
if (commandCode == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
}
@@ -152,7 +118,8 @@ public final class Session2CommandGroup implements Parcelable {
/**
* Gets all commands of this command group.
*/
- public @NonNull Set<Session2Command> getCommands() {
+ @NonNull
+ public Set<Session2Command> getCommands() {
return new HashSet<>(mCommands);
}
@@ -190,7 +157,8 @@ public final class Session2CommandGroup implements Parcelable {
*
* @param command A command to add. Shouldn't be {@code null}.
*/
- public @NonNull Builder addCommand(@NonNull Session2Command command) {
+ @NonNull
+ public Builder addCommand(@NonNull Session2Command command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -204,7 +172,8 @@ public final class Session2CommandGroup implements Parcelable {
* @param commandCode A command code to add.
* Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
*/
- public @NonNull Builder addCommand(@Session2Command.CommandCode int commandCode) {
+ @NonNull
+ public Builder addCommand(int commandCode) {
if (commandCode == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException(
"Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
@@ -214,33 +183,12 @@ public final class Session2CommandGroup implements Parcelable {
}
/**
- * Adds all predefined session commands except for the commands added after the specified
- * version without default implementation. This provides convenient way to add commands
- * with implementation.
- *
- * @param version command version
- * @see Session2Command#COMMAND_VERSION_1
- * @see
- * MediaSession2.Session2Callback#onConnect
- */
- public @NonNull Builder addAllPredefinedCommands(
- @Session2Command.CommandVersion int version) {
- if (version != COMMAND_VERSION_1) {
- throw new IllegalArgumentException("Unknown command version " + version);
- }
- addAllPlayerCommands(version);
- addAllVolumeCommands(version);
- addAllSessionCommands(version);
- addAllLibraryCommands(version);
- return this;
- }
-
- /**
* Removes a command from this group which matches given {@code command}.
*
* @param command A command to find. Shouldn't be {@code null}.
*/
- public @NonNull Builder removeCommand(@NonNull Session2Command command) {
+ @NonNull
+ public Builder removeCommand(@NonNull Session2Command command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -254,7 +202,8 @@ public final class Session2CommandGroup implements Parcelable {
* @param commandCode A command code to find.
* Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
*/
- public @NonNull Builder removeCommand(@Session2Command.CommandCode int commandCode) {
+ @NonNull
+ public Builder removeCommand(int commandCode) {
if (commandCode == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
}
@@ -262,59 +211,13 @@ public final class Session2CommandGroup implements Parcelable {
return this;
}
- @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version) {
- addCommands(version, Session2Command.VERSION_PLAYER_COMMANDS_MAP);
- return this;
- }
-
- @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version,
- boolean includePlaylistCommands) {
- if (includePlaylistCommands) {
- return addAllPlayerCommands(version);
- }
- for (int i = COMMAND_VERSION_1; i <= version; i++) {
- Range include = Session2Command.VERSION_PLAYER_COMMANDS_MAP.get(i);
- Range exclude = Session2Command.VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.get(i);
- for (int code = include.lower; code <= include.upper; code++) {
- if (code < exclude.lower && code > exclude.upper) {
- addCommand(code);
- }
- }
- }
- return this;
- }
-
- @NonNull Builder addAllVolumeCommands(@Session2Command.CommandVersion int version) {
- addCommands(version, Session2Command.VERSION_VOLUME_COMMANDS_MAP);
- return this;
- }
-
- @NonNull Builder addAllSessionCommands(@Session2Command.CommandVersion int version) {
- addCommands(version, Session2Command.VERSION_SESSION_COMMANDS_MAP);
- return this;
- }
-
- @NonNull Builder addAllLibraryCommands(@Session2Command.CommandVersion int version) {
- addCommands(version, Session2Command.VERSION_LIBRARY_COMMANDS_MAP);
- return this;
- }
-
- private void addCommands(
- @Session2Command.CommandVersion int version, ArrayMap<Integer, Range> map) {
- for (int i = COMMAND_VERSION_1; i <= version; i++) {
- Range range = map.get(i);
- for (int code = range.lower; code <= range.upper; code++) {
- addCommand(code);
- }
- }
- }
-
/**
* Builds {@link Session2CommandGroup}.
*
* @return a new {@link Session2CommandGroup}.
*/
- public @NonNull Session2CommandGroup build() {
+ @NonNull
+ public Session2CommandGroup build() {
return new Session2CommandGroup(mCommands);
}
}
diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java
new file mode 100644
index 000000000000..5fe558da12f5
--- /dev/null
+++ b/media/java/android/media/Session2Link.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}.
+ * @hide
+ */
+// @SystemApi
+public final class Session2Link implements Parcelable {
+ private static final String TAG = "Session2Link";
+ private static final boolean DEBUG = MediaSession2.DEBUG;
+
+ public static final Parcelable.Creator<Session2Link> CREATOR =
+ new Parcelable.Creator<Session2Link>() {
+ @Override
+ public Session2Link createFromParcel(Parcel in) {
+ return new Session2Link(in);
+ }
+
+ @Override
+ public Session2Link[] newArray(int size) {
+ return new Session2Link[size];
+ }
+ };
+
+ private final MediaSession2 mSession;
+ private final IMediaSession2 mISession;
+
+ public Session2Link(MediaSession2 session) {
+ mSession = session;
+ mISession = new Session2Stub();
+ }
+
+ Session2Link(Parcel in) {
+ mSession = null;
+ mISession = IMediaSession2.Stub.asInterface(in.readStrongBinder());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mISession.asBinder());
+ }
+
+ @Override
+ public int hashCode() {
+ return mISession.asBinder().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Session2Link)) {
+ return false;
+ }
+ Session2Link other = (Session2Link) obj;
+ return Objects.equals(mISession.asBinder(), other.mISession.asBinder());
+ }
+
+ /** Link to death with mISession */
+ public void linkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
+ if (mISession != null) {
+ try {
+ mISession.asBinder().linkToDeath(recipient, flags);
+ } catch (RemoteException e) {
+ if (DEBUG) {
+ Log.d(TAG, "Session died too early.", e);
+ }
+ }
+ }
+ }
+
+ /** Unlink to death with mISession */
+ public boolean unlinkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
+ if (mISession != null) {
+ return mISession.asBinder().unlinkToDeath(recipient, flags);
+ }
+ return true;
+ }
+
+ /** Interface method for IMediaSession2.connect */
+ public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
+ try {
+ mISession.connect(caller, seq, connectionRequest);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaSession2.disconnect */
+ public void disconnect(final Controller2Link caller, int seq) {
+ try {
+ mISession.disconnect(caller, seq);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaSession2.sendSessionCommand */
+ public void sendSessionCommand(final Controller2Link caller, final int seq,
+ final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+ try {
+ mISession.sendSessionCommand(caller, seq, command, args, resultReceiver);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Interface method for IMediaSession2.sendSessionCommand */
+ public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+ try {
+ mISession.cancelSessionCommand(caller, seq);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Stub implementation for IMediaSession2.connect */
+ public void onConnect(final Controller2Link caller, int seq, Bundle connectionRequest) {
+ mSession.onConnect(caller, seq, connectionRequest);
+ }
+
+ /** Stub implementation for IMediaSession2.disconnect */
+ public void onDisconnect(final Controller2Link caller, int seq) {
+ mSession.onDisconnect(caller, seq);
+ }
+
+ /** Stub implementation for IMediaSession2.sendSessionCommand */
+ public void onSessionCommand(final Controller2Link caller, final int seq,
+ final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+ mSession.onSessionCommand(caller, seq, command, args, resultReceiver);
+ }
+
+ /** Stub implementation for IMediaSession2.cancelSessionCommand */
+ public void onCancelCommand(final Controller2Link caller, final int seq) {
+ mSession.onCancelCommand(caller, seq);
+ }
+
+ private class Session2Stub extends IMediaSession2.Stub {
+ @Override
+ public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
+ Session2Link.this.onConnect(caller, seq, connectionRequest);
+ }
+
+ @Override
+ public void disconnect(final Controller2Link caller, int seq) {
+ Session2Link.this.onDisconnect(caller, seq);
+ }
+
+ @Override
+ public void sendSessionCommand(final Controller2Link caller, final int seq,
+ final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+ Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+ }
+
+ @Override
+ public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+ Session2Link.this.onCancelCommand(caller, seq);
+ }
+ }
+}
diff --git a/media/java/android/media/Session2Token.aidl b/media/java/android/media/Session2Token.aidl
new file mode 100644
index 000000000000..c5980e9e77fd
--- /dev/null
+++ b/media/java/android/media/Session2Token.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable Session2Token;
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index af140789ea85..4634c6963675 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -24,7 +24,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -39,8 +38,9 @@ import java.util.Objects;
* If it's representing a session service, it may not be ongoing.
* <p>
* This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx/">Support Library</a> instead.
- * {@link androidx.media2.SessionToken} for consistent behavior across all devices.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
* <p>
* This may be passed to apps by the session owner to allow them to create a
* {@link MediaController2} to communicate with the session.
@@ -85,12 +85,12 @@ public final class Session2Token implements Parcelable {
public static final int TYPE_SESSION = 0;
/**
- * Type for {@link MediaSessionService2}.
+ * Type for {@link MediaSession2Service}.
*/
public static final int TYPE_SESSION_SERVICE = 1;
/**
- * Type for {@link MediaLibraryService2}.
+ * Type for {@link MediaLibrary2Service}.
*/
public static final int TYPE_LIBRARY_SERVICE = 2;
@@ -98,12 +98,12 @@ public final class Session2Token implements Parcelable {
private final @TokenType int mType;
private final String mPackageName;
private final String mServiceName;
- private final IBinder mISession;
+ private final Session2Link mSessionLink;
private final ComponentName mComponentName;
/**
- * Constructor for the token. You can create token of {@link MediaSessionService2},
- * {@link MediaLibraryService2} for {@link MediaController2} or {@link MediaBrowser2}.
+ * Constructor for the token with type {@link #TYPE_SESSION_SERVICE} or
+ * {@link #TYPE_LIBRARY_SERVICE}.
*
* @param context The context.
* @param serviceComponent The component name of the service.
@@ -141,27 +141,26 @@ public final class Session2Token implements Parcelable {
mServiceName = serviceComponent.getClassName();
mUid = uid;
mType = type;
- mISession = null;
+ mSessionLink = null;
}
- // TODO: Uncomment below
-// Session2Token(int uid, int type, String packageName, IMediaSession2 iSession) {
-// mUid = uid;
-// mType = type;
-// mPackageName = packageName;
-// mServiceName = null;
-// mComponentName = null;
-// mISession = iSession.asBinder();
-// }
+ Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
+ mUid = uid;
+ mType = type;
+ mPackageName = packageName;
+ mServiceName = null;
+ mComponentName = null;
+ mSessionLink = sessionLink;
+ }
Session2Token(Parcel in) {
mUid = in.readInt();
mType = in.readInt();
mPackageName = in.readString();
mServiceName = in.readString();
- // TODO: Uncomment below and stop hardcode mISession
- mISession = null;
- //mISession = ISession.Stub.asInterface(in.readStrongBinder());
+ // TODO: Uncomment below and stop hardcode mSessionLink
+ mSessionLink = null;
+ //mSessionLink = ISession.Stub.asInterface(in.readStrongBinder());
mComponentName = ComponentName.unflattenFromString(in.readString());
}
@@ -172,7 +171,7 @@ public final class Session2Token implements Parcelable {
dest.writeString(mPackageName);
dest.writeString(mServiceName);
// TODO: Uncomment below
- //dest.writeStrongBinder(mISession.asBinder());
+ //dest.writeStrongBinder(mSessionLink.asBinder());
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
}
@@ -183,7 +182,7 @@ public final class Session2Token implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mType, mUid, mPackageName, mServiceName, mISession);
+ return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink);
}
@Override
@@ -196,13 +195,13 @@ public final class Session2Token implements Parcelable {
&& TextUtils.equals(mPackageName, other.mPackageName)
&& TextUtils.equals(mServiceName, other.mServiceName)
&& mType == other.mType
- && Objects.equals(mISession, other.mISession);
+ && Objects.equals(mSessionLink, other.mSessionLink);
}
@Override
public String toString() {
return "Session2Token {pkg=" + mPackageName + " type=" + mType
- + " service=" + mServiceName + " IMediaSession2=" + mISession + "}";
+ + " service=" + mServiceName + " Session2Link=" + mSessionLink + "}";
}
/**
@@ -249,8 +248,8 @@ public final class Session2Token implements Parcelable {
/**
* @hide
*/
- public Object getBinder() {
- return mISession;
+ public Session2Link getSessionLink() {
+ return mSessionLink;
}
private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface,
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index f07076ad14aa..ccf49bd774a8 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -36,6 +36,7 @@ import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Build;
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
@@ -362,27 +363,27 @@ public class ThumbnailUtils {
}
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
return 1;
}
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
return 1;
}
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void closeSilently(ParcelFileDescriptor c) {
IoUtils.closeQuietly(c);
}
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static ParcelFileDescriptor makeInputStream(
Uri uri, ContentResolver cr) {
try {
@@ -396,7 +397,7 @@ public class ThumbnailUtils {
* Transform source Bitmap to targeted width and height.
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static Bitmap transform(Matrix scaler,
Bitmap source,
int targetWidth,
@@ -502,7 +503,7 @@ public class ThumbnailUtils {
}
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static void createThumbnailFromEXIF(String filePath, int targetSize,
int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) {
}
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 7fb3aa6d79f9..1c6210e0c060 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -165,6 +165,20 @@ public class AudioMix {
}
/** @hide */
+ public boolean isRoutedToDevice(int deviceType, @NonNull String deviceAddress) {
+ if ((mRouteFlags & ROUTE_FLAG_RENDER) != ROUTE_FLAG_RENDER) {
+ return false;
+ }
+ if (deviceType != mDeviceSystemType) {
+ return false;
+ }
+ if (!deviceAddress.equals(mDeviceAddress)) {
+ return false;
+ }
+ return true;
+ }
+
+ /** @hide */
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 6103f55745f9..65f3294800f5 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -22,6 +22,7 @@ import android.annotation.SystemApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioFocusInfo;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -323,6 +324,80 @@ public class AudioPolicy {
}
}
+ /**
+ * @hide
+ * Configures the audio framework so that all audio stream originating from the given UID
+ * can only come from a set of audio devices.
+ * For this routing to be operational, a number of {@link AudioMix} instances must have been
+ * previously registered on this policy, and routed to a super-set of the given audio devices
+ * with {@link AudioMix.Builder#setDevice(android.media.AudioDeviceInfo)}. Note that having
+ * multiple devices in the list doesn't imply the signals will be duplicated on the different
+ * audio devices, final routing will depend on the {@link AudioAttributes} of the sounds being
+ * 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.
+ */
+ @SystemApi
+ public int setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
+ if (devices == null) {
+ throw new IllegalArgumentException("Illegal null list of audio devices");
+ }
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+ }
+ final int[] deviceTypes = new int[devices.size()];
+ final String[] deviceAdresses = new String[devices.size()];
+ int i = 0;
+ for (AudioDeviceInfo device : devices) {
+ if (device == null) {
+ throw new IllegalArgumentException(
+ "Illegal null AudioDeviceInfo in setUidDeviceAffinity");
+ }
+ deviceTypes[i] =
+ AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
+ deviceAdresses[i] = device.getAddress();
+ i++;
+ }
+ final IAudioService service = getService();
+ try {
+ final int status = service.setUidDeviceAffinity(this.cb(),
+ uid, deviceTypes, deviceAdresses);
+ return status;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setUidDeviceAffinity", e);
+ return AudioManager.ERROR;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * 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.
+ */
+ @SystemApi
+ public int removeUidDeviceAffinity(int uid) {
+ synchronized (mLock) {
+ if (mStatus != POLICY_STATUS_REGISTERED) {
+ throw new IllegalStateException("Cannot use unregistered AudioPolicy");
+ }
+ final IAudioService service = getService();
+ try {
+ final int status = service.removeUidDeviceAffinity(this.cb(), uid);
+ return status;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in removeUidDeviceAffinity", e);
+ return AudioManager.ERROR;
+ }
+ }
+ }
+
public void setRegistration(String regId) {
synchronized (mLock) {
mRegistrationId = regId;
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 861a8cea7db2..e61bf5b48223 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -48,9 +48,10 @@ interface ISessionController {
PendingIntent getLaunchPendingIntent();
long getFlags();
ParcelableVolumeInfo getVolumeAttributes();
- void adjustVolume(String packageName, ISessionControllerCallback caller,
- boolean asSystemService, int direction, int flags);
- void setVolumeTo(String packageName, ISessionControllerCallback caller,
+ void adjustVolume(String packageName, String opPackageName,
+ in ISessionControllerCallback caller, boolean asSystemService, int direction,
+ int flags);
+ void setVolumeTo(String packageName, String opPackageName, in ISessionControllerCallback caller,
int value, int flags);
// These commands are for the TransportControls
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 4ced7bee2cbd..51148e2f1af4 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -17,6 +17,7 @@ package android.media.session;
import android.content.ComponentName;
import android.media.IRemoteVolumeController;
+import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
@@ -32,12 +33,14 @@ import android.view.KeyEvent;
*/
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
+ void notifySession2Created(in Session2Token sessionToken);
List<IBinder> getSessions(in ComponentName compName, int userId);
void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
boolean needWakeLock);
- void dispatchVolumeKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
- int stream, boolean musicOnly);
- void dispatchAdjustVolume(String packageName, int suggestedStream, int delta, int flags);
+ void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
+ in KeyEvent keyEvent, int stream, boolean musicOnly);
+ void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
+ int delta, int flags);
void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
int userId);
void removeSessionsListener(in IActiveSessionsListener listener);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b457357600fe..181ee5327547 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -153,7 +153,7 @@ public final class MediaController {
return false;
}
try {
- return mSessionBinder.sendMediaButton(mContext.getOpPackageName(), mCbStub,
+ return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
asSystemService, keyEvent);
} catch (RemoteException e) {
// System is dead. =(
@@ -186,8 +186,12 @@ public final class MediaController {
break;
}
try {
- mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true,
- direction, AudioManager.FLAG_SHOW_UI);
+ // Note: Need both package name and OP package name. Package name is used for
+ // RemoteUserInfo, and OP package name is used for AudioService's internal
+ // AppOpsManager usages.
+ mSessionBinder.adjustVolume(mContext.getPackageName(),
+ mContext.getOpPackageName(), mCbStub, true, direction,
+ AudioManager.FLAG_SHOW_UI);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy", e);
}
@@ -197,8 +201,11 @@ public final class MediaController {
final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
| AudioManager.FLAG_FROM_KEY;
try {
- mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true, 0,
- flags);
+ // Note: Need both package name and OP package name. Package name is used for
+ // RemoteUserInfo, and OP package name is used for AudioService's internal
+ // AppOpsManager usages.
+ mSessionBinder.adjustVolume(mContext.getPackageName(),
+ mContext.getOpPackageName(), mCbStub, true, 0, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy", e);
}
@@ -367,7 +374,11 @@ public final class MediaController {
*/
public void setVolumeTo(int value, int flags) {
try {
- mSessionBinder.setVolumeTo(mContext.getOpPackageName(), mCbStub, value, flags);
+ // Note: Need both package name and OP package name. Package name is used for
+ // RemoteUserInfo, and OP package name is used for AudioService's internal
+ // AppOpsManager usages.
+ mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
+ mCbStub, value, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling setVolumeTo.", e);
}
@@ -388,8 +399,11 @@ public final class MediaController {
*/
public void adjustVolume(int direction, int flags) {
try {
- mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, false, direction,
- flags);
+ // Note: Need both package name and OP package name. Package name is used for
+ // RemoteUserInfo, and OP package name is used for AudioService's internal
+ // AppOpsManager usages.
+ mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
+ mCbStub, false, direction, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
}
@@ -455,7 +469,7 @@ public final class MediaController {
throw new IllegalArgumentException("command cannot be null or empty");
}
try {
- mSessionBinder.sendCommand(mContext.getOpPackageName(), mCbStub, command, args, cb);
+ mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
} catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCommand.", e);
}
@@ -521,7 +535,7 @@ public final class MediaController {
if (!mCbRegistered) {
try {
- mSessionBinder.registerCallbackListener(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
mCbRegistered = true;
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerCallback", e);
@@ -668,7 +682,7 @@ public final class MediaController {
*/
public void prepare() {
try {
- mSessionBinder.prepare(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare.", e);
}
@@ -692,7 +706,7 @@ public final class MediaController {
"You must specify a non-empty String for prepareFromMediaId.");
}
try {
- mSessionBinder.prepareFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
+ mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
@@ -719,7 +733,7 @@ public final class MediaController {
query = "";
}
try {
- mSessionBinder.prepareFromSearch(mContext.getOpPackageName(), mCbStub, query,
+ mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
@@ -744,7 +758,7 @@ public final class MediaController {
"You must specify a non-empty Uri for prepareFromUri.");
}
try {
- mSessionBinder.prepareFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
+ mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
}
@@ -755,7 +769,7 @@ public final class MediaController {
*/
public void play() {
try {
- mSessionBinder.play(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.play(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play.", e);
}
@@ -774,7 +788,7 @@ public final class MediaController {
"You must specify a non-empty String for playFromMediaId.");
}
try {
- mSessionBinder.playFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
+ mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
@@ -797,7 +811,7 @@ public final class MediaController {
query = "";
}
try {
- mSessionBinder.playFromSearch(mContext.getOpPackageName(), mCbStub, query, extras);
+ mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + query + ").", e);
}
@@ -816,7 +830,7 @@ public final class MediaController {
"You must specify a non-empty Uri for playFromUri.");
}
try {
- mSessionBinder.playFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
+ mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + uri + ").", e);
}
@@ -828,7 +842,7 @@ public final class MediaController {
*/
public void skipToQueueItem(long id) {
try {
- mSessionBinder.skipToQueueItem(mContext.getOpPackageName(), mCbStub, id);
+ mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
}
@@ -840,7 +854,7 @@ public final class MediaController {
*/
public void pause() {
try {
- mSessionBinder.pause(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.pause(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling pause.", e);
}
@@ -852,7 +866,7 @@ public final class MediaController {
*/
public void stop() {
try {
- mSessionBinder.stop(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.stop(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling stop.", e);
}
@@ -865,7 +879,7 @@ public final class MediaController {
*/
public void seekTo(long pos) {
try {
- mSessionBinder.seekTo(mContext.getOpPackageName(), mCbStub, pos);
+ mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling seekTo.", e);
}
@@ -877,7 +891,7 @@ public final class MediaController {
*/
public void fastForward() {
try {
- mSessionBinder.fastForward(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling fastForward.", e);
}
@@ -888,7 +902,7 @@ public final class MediaController {
*/
public void skipToNext() {
try {
- mSessionBinder.next(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.next(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling next.", e);
}
@@ -900,7 +914,7 @@ public final class MediaController {
*/
public void rewind() {
try {
- mSessionBinder.rewind(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling rewind.", e);
}
@@ -911,7 +925,7 @@ public final class MediaController {
*/
public void skipToPrevious() {
try {
- mSessionBinder.previous(mContext.getOpPackageName(), mCbStub);
+ mSessionBinder.previous(mContext.getPackageName(), mCbStub);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling previous.", e);
}
@@ -926,7 +940,7 @@ public final class MediaController {
*/
public void setRating(Rating rating) {
try {
- mSessionBinder.rate(mContext.getOpPackageName(), mCbStub, rating);
+ mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling rate.", e);
}
@@ -961,7 +975,7 @@ public final class MediaController {
throw new IllegalArgumentException("CustomAction cannot be null.");
}
try {
- mSessionBinder.sendCustomAction(mContext.getOpPackageName(), mCbStub, action, args);
+ mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
} catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCustomAction.", e);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6a06dd07d22f..ef5cf008de88 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -26,6 +26,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.media.AudioManager;
import android.media.IRemoteVolumeController;
+import android.media.MediaSession2;
+import android.media.Session2Token;
import android.media.browse.MediaBrowser;
import android.os.Handler;
import android.os.IBinder;
@@ -102,6 +104,30 @@ public final class MediaSessionManager {
}
/**
+ * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
+ * created.
+ * <p>
+ * Do not use this API directly, but create a new instance through the
+ * {@link MediaSession2.Builder} instead.
+ *
+ * @param token newly created session2 token
+ * @hide
+ */
+ public void notifySession2Created(@NonNull Session2Token token) {
+ if (token == null) {
+ throw new IllegalArgumentException("token shouldn't be null");
+ }
+ if (token.getType() != Session2Token.TYPE_SESSION) {
+ throw new IllegalArgumentException("token's type should be TYPE_SESSION");
+ }
+ try {
+ mService.notifySession2Created(token);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get a list of controllers for all ongoing sessions. The controllers will
* be provided in priority order with the most important controller at index
* 0.
@@ -312,7 +338,7 @@ public final class MediaSessionManager {
private void dispatchMediaKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
boolean needWakeLock) {
try {
- mService.dispatchMediaKeyEvent(mContext.getOpPackageName(), asSystemService, keyEvent,
+ mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
needWakeLock);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send key event.", e);
@@ -348,8 +374,8 @@ public final class MediaSessionManager {
private void dispatchVolumeKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
int stream, boolean musicOnly) {
try {
- mService.dispatchVolumeKeyEvent(mContext.getOpPackageName(), asSystemService, keyEvent,
- stream, musicOnly);
+ mService.dispatchVolumeKeyEvent(mContext.getPackageName(), mContext.getOpPackageName(),
+ asSystemService, keyEvent, stream, musicOnly);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send volume key event.", e);
}
@@ -369,8 +395,8 @@ public final class MediaSessionManager {
*/
public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
try {
- mService.dispatchAdjustVolume(mContext.getOpPackageName(), suggestedStream, direction,
- flags);
+ mService.dispatchAdjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
+ suggestedStream, direction, flags);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send adjust volume.", e);
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7481fff74765..f75f69b4f2ee 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -95,14 +95,16 @@ cc_library_shared {
],
shared_libs: [
- "android.hardware.cas@1.0", // for CasManager. VNDK???
- "android.hardware.cas.native@1.0", // CasManager. VNDK???
+ // MediaCas
+ "android.hardware.cas@1.0",
+ "android.hardware.cas.native@1.0",
"android.hidl.allocator@1.0",
+ "libhidlbase",
"libhidlmemory",
- "libbinder",
- "libgui", // for VideoFrameScheduler
- "libhidlbase", // VNDK???
- "libpowermanager", // for JWakeLock. to be removed
+
+ "libpowermanager", // Used by JWakeLock. Will be replace with public SDJ API.
+ "libmediametrics", // Used by MediaMetrics. Will be replaced with stable C API.
+ "libbinder", // Used by JWakeLock and MediaMetrics.
"libutils", // Have to use shared lib to make libandroid_runtime behave correctly.
// Otherwise, AndroidRuntime::getJNIEnv() will return NULL.
@@ -124,7 +126,6 @@ cc_library_shared {
"libmedia_helper",
"libmedia_player2_util",
"libmediaextractor",
- "libmediametrics",
"libmediaplayer2",
"libmediaplayer2-protos",
"libmediandk_utils",
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
index 6375ed3f3c83..4cee62e7dcbf 100644
--- a/media/tests/MtpTests/Android.mk
+++ b/media/tests/MtpTests/Android.mk
@@ -5,7 +5,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
LOCAL_PACKAGE_NAME := MtpTests
LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/media/tests/MtpTests/AndroidManifest.xml b/media/tests/MtpTests/AndroidManifest.xml
index 21e2b0115878..72e03f186c35 100644
--- a/media/tests/MtpTests/AndroidManifest.xml
+++ b/media/tests/MtpTests/AndroidManifest.xml
@@ -25,7 +25,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.mtp"
android:label="MtpTests"/>
</manifest>
diff --git a/media/tests/MtpTests/AndroidTest.xml b/media/tests/MtpTests/AndroidTest.xml
index a61a3b49c8f7..22638bca1379 100644
--- a/media/tests/MtpTests/AndroidTest.xml
+++ b/media/tests/MtpTests/AndroidTest.xml
@@ -10,6 +10,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.mtp"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration> \ No newline at end of file
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index 566d1c63fff3..1f58bdec9838 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -18,20 +18,19 @@ package android.mtp;
import android.os.FileUtils;
import android.os.UserHandle;
import android.os.storage.StorageVolume;
-import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
-import org.junit.runners.MethodSorters;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.junit.runners.MethodSorters;
import java.io.File;
import java.io.FileOutputStream;
@@ -39,8 +38,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
/**
* Tests for MtpStorageManager functionality.
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 96c9c1c85a60..09362566d915 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -22,6 +22,7 @@ cc_library_shared {
name: "libwebviewchromium_plat_support",
srcs: [
+ "draw_functor.cpp",
"draw_gl_functor.cpp",
"draw_vk_functor.cpp",
"functor_utils.cpp",
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index 8d48a58ac293..6afd8837594c 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -129,31 +129,31 @@ struct AwDrawFn_PostDrawVkParams {
// Called on render thread while UI thread is blocked. Called for both GL and
// VK.
-typedef void AwDrawFn_OnSync(int functor, AwDrawFn_OnSyncParams* params);
+typedef void AwDrawFn_OnSync(int functor, void* data, AwDrawFn_OnSyncParams* params);
// Called on render thread when either the context is destroyed _or_ when the
// functor's last reference goes away. Will always be called with an active
// context. Called for both GL and VK.
-typedef void AwDrawFn_OnContextDestroyed(int functor);
+typedef void AwDrawFn_OnContextDestroyed(int functor, void* data);
// Called on render thread when the last reference to the handle goes away and
-// the handle is considered irrevocably destroyed. Will always be proceeded by
+// the handle is considered irrevocably destroyed. Will always be preceded by
// a call to OnContextDestroyed if this functor had ever been drawn. Called for
// both GL and VK.
-typedef void AwDrawFn_OnDestroyed(int functor);
+typedef void AwDrawFn_OnDestroyed(int functor, void* data);
// Only called for GL.
-typedef void AwDrawFn_DrawGL(int functor, AwDrawFn_DrawGLParams* params);
+typedef void AwDrawFn_DrawGL(int functor, void* data, AwDrawFn_DrawGLParams* params);
// Initialize vulkan state. Needs to be called again after any
// OnContextDestroyed. Only called for Vulkan.
-typedef void AwDrawFn_InitVk(int functor, AwDrawFn_InitVkParams* params);
+typedef void AwDrawFn_InitVk(int functor, void* data, AwDrawFn_InitVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_DrawVk(int functor, AwDrawFn_DrawVkParams* params);
+typedef void AwDrawFn_DrawVk(int functor, void* data, AwDrawFn_DrawVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_PostDrawVk(int functor,
+typedef void AwDrawFn_PostDrawVk(int functor, void* data,
AwDrawFn_PostDrawVkParams* params);
struct AwDrawFnFunctorCallbacks {
@@ -176,7 +176,7 @@ enum AwDrawFnRenderMode {
typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
-typedef int AwDrawFn_CreateFunctor(AwDrawFnFunctorCallbacks* functor_callbacks);
+typedef int AwDrawFn_CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
new file mode 100644
index 000000000000..820bac509d2e
--- /dev/null
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#include "draw_fn.h"
+
+#include <jni.h>
+#include <private/hwui/WebViewFunctor.h>
+#include <utils/Log.h>
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#define COMPILE_ASSERT(expr, err) \
+__unused static const char (err)[(expr) ? 1 : -1] = "";
+
+namespace android {
+namespace {
+
+struct SupportData {
+ void* const data;
+ AwDrawFnFunctorCallbacks callbacks;
+};
+
+void onSync(int functor, void* data,
+ const uirenderer::WebViewSyncData& syncData) {
+ AwDrawFn_OnSyncParams params = {
+ .version = kAwDrawFnVersion,
+ .apply_force_dark = syncData.applyForceDark,
+ };
+ SupportData* support = static_cast<SupportData*>(data);
+ support->callbacks.on_sync(functor, support->data, &params);
+}
+
+void onContextDestroyed(int functor, void* data) {
+ SupportData* support = static_cast<SupportData*>(data);
+ support->callbacks.on_context_destroyed(functor, support->data);
+}
+
+void onDestroyed(int functor, void* data) {
+ SupportData* support = static_cast<SupportData*>(data);
+ support->callbacks.on_destroyed(functor, support->data);
+ delete support;
+}
+
+void draw_gl(int functor, void* data,
+ const uirenderer::DrawGlInfo& draw_gl_params) {
+ AwDrawFn_DrawGLParams params = {
+ .version = kAwDrawFnVersion,
+ .clip_left = draw_gl_params.clipLeft,
+ .clip_top = draw_gl_params.clipTop,
+ .clip_right = draw_gl_params.clipRight,
+ .clip_bottom = draw_gl_params.clipBottom,
+ .width = draw_gl_params.width,
+ .height = draw_gl_params.height,
+ .is_layer = draw_gl_params.isLayer,
+ };
+ COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_gl_params.transform),
+ mismatched_transform_matrix_sizes);
+ for (int i = 0; i < NELEM(params.transform); ++i) {
+ params.transform[i] = draw_gl_params.transform[i];
+ }
+ SupportData* support = static_cast<SupportData*>(data);
+ support->callbacks.draw_gl(functor, support->data, &params);
+}
+
+int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
+ static bool callbacks_initialized = false;
+ static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
+ .onSync = &onSync,
+ .onContextDestroyed = &onContextDestroyed,
+ .onDestroyed = &onDestroyed,
+ };
+ if (!callbacks_initialized) {
+ switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+ case uirenderer::RenderMode::OpenGL_ES:
+ webview_functor_callbacks.gles.draw = &draw_gl;
+ break;
+ case uirenderer::RenderMode::Vulkan:
+ break;
+ }
+ callbacks_initialized = true;
+ }
+ SupportData* support = new SupportData{
+ .data = data,
+ .callbacks = *functor_callbacks,
+ };
+ int functor = uirenderer::WebViewFunctor_create(
+ support, webview_functor_callbacks,
+ uirenderer::WebViewFunctor_queryPlatformRenderMode());
+ if (functor <= 0) delete support;
+ return functor;
+}
+
+void ReleaseFunctor(int functor) {
+ uirenderer::WebViewFunctor_release(functor);
+}
+
+AwDrawFnRenderMode QueryRenderMode(void) {
+ switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+ case uirenderer::RenderMode::OpenGL_ES:
+ return AW_DRAW_FN_RENDER_MODE_OPENGL_ES;
+ case uirenderer::RenderMode::Vulkan:
+ return AW_DRAW_FN_RENDER_MODE_VULKAN;
+ }
+}
+
+jlong GetDrawFnFunctionTable() {
+ static AwDrawFnFunctionTable function_table = {
+ .version = kAwDrawFnVersion,
+ .query_render_mode = &QueryRenderMode,
+ .create_functor = &CreateFunctor,
+ .release_functor = &ReleaseFunctor,
+ };
+ return reinterpret_cast<intptr_t>(&function_table);
+}
+
+const char kClassName[] = "com/android/webview/chromium/DrawFunctor";
+const JNINativeMethod kJniMethods[] = {
+ {"nativeGetFunctionTable", "()J",
+ reinterpret_cast<void*>(GetDrawFnFunctionTable)},
+};
+
+} // namespace
+
+void RegisterDrawFunctor(JNIEnv* env) {
+ jclass clazz = env->FindClass(kClassName);
+ LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
+
+ int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
+}
+
+} // namespace android
diff --git a/native/webview/plat_support/jni_entry_point.cpp b/native/webview/plat_support/jni_entry_point.cpp
index 4771be1bc258..9599fa6da516 100644
--- a/native/webview/plat_support/jni_entry_point.cpp
+++ b/native/webview/plat_support/jni_entry_point.cpp
@@ -21,6 +21,7 @@
namespace android {
+void RegisterDrawFunctor(JNIEnv* env);
void RegisterDrawGLFunctor(JNIEnv* env);
void RegisterGraphicsUtils(JNIEnv* env);
@@ -30,6 +31,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint ret = vm->AttachCurrentThread(&env, NULL);
LOG_ALWAYS_FATAL_IF(ret != JNI_OK, "AttachCurrentThread failed");
+ android::RegisterDrawFunctor(env);
android::RegisterDrawGLFunctor(env);
android::RegisterGraphicsUtils(env);
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 3c0a2973ad40..0c352043f2a3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,11 +20,9 @@ import android.content.Context;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.car.CarNotificationEntryManager;
import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.statusbar.car.CarFacetButtonController;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.volume.CarVolumeDialogComponent;
@@ -65,16 +63,16 @@ public class CarSystemUIFactory extends SystemUIFactory {
}
@Override
- public NotificationEntryManager provideNotificationEntryManager(Context context) {
- return new CarNotificationEntryManager(context);
- }
-
- @Override
public NotificationInterruptionStateProvider provideNotificationInterruptionStateProvider(
Context context) {
return new CarNotificationInterruptionStateProvider(context);
}
+ @Override
+ public boolean provideAllowNotificationLongPress() {
+ return false;
+ }
+
@Module
protected static class ContextHolder {
private Context mContext;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
deleted file mode 100644
index 323cae0067d8..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ /dev/null
@@ -1,41 +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.
- */
-
-package com.android.systemui.car;
-
-import android.content.Context;
-
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-
-public class CarNotificationEntryManager extends NotificationEntryManager {
- public CarNotificationEntryManager(Context context) {
- super(context);
- }
-
- /**
- * Returns the
- * {@link ExpandableNotificationRow.LongPressListener} that will
- * be triggered when a notification card is long-pressed.
- */
- @Override
- public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
- // For the automative use case, we do not want to the user to be able to interact with
- // a notification other than a regular click. As a result, just return null for the
- // long click listener.
- return null;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
index d5dd3c3eaca0..4ef926fae816 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -28,7 +28,7 @@ import androidx.annotation.IdRes;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher;
/**
* A view that forms the header of the notification panel. This view will ensure that any
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
index 5bf30ca10694..b36a7da35acf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/AssitantButton.java
@@ -45,9 +45,7 @@ public class AssitantButton extends CarFacetButton {
Log.d(TAG, "IVoiceInteractionSessionShowCallback onShown()");
}
};
-
- private static final String EXTRA_CAR_PUSH_TO_TALK =
- "com.android.car.input.EXTRA_CAR_PUSH_TO_TALK";
+
private final AssistUtils mAssistUtils;
public AssitantButton(Context context, AttributeSet attrs) {
@@ -60,7 +58,6 @@ public class AssitantButton extends CarFacetButton {
private void showAssistant() {
final Bundle args = new Bundle();
- args.putBoolean(EXTRA_CAR_PUSH_TO_TALK, true);
mAssistUtils.showSessionForActiveService(args,
SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, /*activityToken=*/ null);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7028999c159c..dbddf71d342c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -280,7 +280,9 @@ public class CarStatusBar extends StatusBar implements
buildNavBarContent();
attachNavBarWindows();
- mNavigationBarController.createNavigationBars();
+ // There has been a car customized nav bar on the default display, so just create nav bars
+ // on external displays.
+ mNavigationBarController.createNavigationBars(false /* includeDefaultDisplay */);
}
private void buildNavBarContent() {
@@ -447,12 +449,6 @@ public class CarStatusBar extends StatusBar implements
}
}
-
- @Override
- public View getNavigationBarWindow() {
- return mNavigationBarWindow;
- }
-
@Override
protected View.OnTouchListener getStatusBarWindowTouchListener() {
// Usually, a touch on the background window will dismiss the notification shade. However,
diff --git a/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java b/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java
new file mode 100644
index 000000000000..50cb0abd6329
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ext.services.notification;
+
+import android.annotation.NonNull;
+import android.util.ArrayMap;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextLinks;
+
+/**
+ * Counts the entity types for smart actions. Some entity types are considered the same
+ * type, like {@link TextClassifier#TYPE_DATE} and {@link TextClassifier#TYPE_DATE_TIME}.
+ */
+class EntityTypeCounter {
+
+ private static final ArrayMap<String, String> ENTITY_TYPE_MAPPING = new ArrayMap<>();
+
+ static {
+ ENTITY_TYPE_MAPPING.put(TextClassifier.TYPE_DATE_TIME, TextClassifier.TYPE_DATE);
+ }
+
+ private final ArrayMap<String, Integer> mEntityTypeCount = new ArrayMap<>();
+
+
+ void increment(@NonNull String entityType) {
+ entityType = convertToBaseEntityType(entityType);
+ if (mEntityTypeCount.containsKey(entityType)) {
+ mEntityTypeCount.put(entityType, mEntityTypeCount.get(entityType) + 1);
+ } else {
+ mEntityTypeCount.put(entityType, 1);
+ }
+ }
+
+ int getCount(@NonNull String entityType) {
+ entityType = convertToBaseEntityType(entityType);
+ return mEntityTypeCount.getOrDefault(entityType, 0);
+ }
+
+ @NonNull
+ private String convertToBaseEntityType(@NonNull String entityType) {
+ return ENTITY_TYPE_MAPPING.getOrDefault(entityType, entityType);
+ }
+
+ /**
+ * Given the links extracted from a piece of text, returns the frequency of each entity
+ * type.
+ */
+ @NonNull
+ static EntityTypeCounter fromTextLinks(@NonNull TextLinks links) {
+ EntityTypeCounter counter = new EntityTypeCounter();
+ for (TextLinks.TextLink link : links.getLinks()) {
+ if (link.getEntityCount() == 0) {
+ continue;
+ }
+ String entityType = link.getEntity(0);
+ counter.increment(entityType);
+ }
+ return counter;
+ }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index b041842c45b9..56c415816558 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -26,7 +26,6 @@ import android.os.Parcelable;
import android.os.Process;
import android.service.notification.NotificationAssistantService;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.LruCache;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassification;
@@ -356,7 +355,7 @@ public class SmartActionsHelper {
TextClassifier.HINT_TEXT_IS_NOT_EDITABLE)))
.build();
TextLinks links = mTextClassifier.generateLinks(textLinksRequest);
- ArrayMap<String, Integer> entityTypeFrequency = getEntityTypeFrequency(links);
+ EntityTypeCounter entityTypeCounter = EntityTypeCounter.fromTextLinks(links);
ArrayList<Notification.Action> actions = new ArrayList<>();
for (TextLinks.TextLink link : links.getLinks()) {
@@ -364,7 +363,7 @@ public class SmartActionsHelper {
// case where a notification contains e.g. a list of phone numbers. In such cases, the
// user likely wants to act on the whole list rather than an individual entity.
if (link.getEntityCount() == 0
- || entityTypeFrequency.get(link.getEntity(0)) != 1) {
+ || entityTypeCounter.getCount(link.getEntity(0)) != 1) {
continue;
}
@@ -398,25 +397,4 @@ public class SmartActionsHelper {
}
return actions;
}
-
- /**
- * Given the links extracted from a piece of text, returns the frequency of each entity
- * type.
- */
- @NonNull
- private ArrayMap<String, Integer> getEntityTypeFrequency(@NonNull TextLinks links) {
- ArrayMap<String, Integer> entityTypeCount = new ArrayMap<>();
- for (TextLinks.TextLink link : links.getLinks()) {
- if (link.getEntityCount() == 0) {
- continue;
- }
- String entityType = link.getEntity(0);
- if (entityTypeCount.containsKey(entityType)) {
- entityTypeCount.put(entityType, entityTypeCount.get(entityType) + 1);
- } else {
- entityTypeCount.put(entityType, 1);
- }
- }
- return entityTypeCount;
- }
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java
new file mode 100644
index 000000000000..2d29c7b77759
--- /dev/null
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ext.services.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.TextClassifier;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class EntityTypeCounterTest {
+ private EntityTypeCounter mCounter;
+
+ @Before
+ public void setup() {
+ mCounter = new EntityTypeCounter();
+ }
+
+ @Test
+ public void testIncrementAndGetCount() {
+ mCounter.increment(TextClassifier.TYPE_URL);
+ mCounter.increment(TextClassifier.TYPE_URL);
+ mCounter.increment(TextClassifier.TYPE_URL);
+
+ mCounter.increment(TextClassifier.TYPE_PHONE);
+ mCounter.increment(TextClassifier.TYPE_PHONE);
+
+ assertThat(mCounter.getCount(TextClassifier.TYPE_URL)).isEqualTo(3);
+ assertThat(mCounter.getCount(TextClassifier.TYPE_PHONE)).isEqualTo(2);
+ assertThat(mCounter.getCount(TextClassifier.TYPE_DATE_TIME)).isEqualTo(0);
+ }
+
+ @Test
+ public void testIncrementAndGetCount_typeDateAndDateTime() {
+ mCounter.increment(TextClassifier.TYPE_DATE_TIME);
+ mCounter.increment(TextClassifier.TYPE_DATE);
+
+ assertThat(mCounter.getCount(TextClassifier.TYPE_DATE_TIME)).isEqualTo(2);
+ assertThat(mCounter.getCount(TextClassifier.TYPE_DATE)).isEqualTo(2);
+ }
+}
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
index 1a4d7b7dee14..b063e13bcc12 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
@@ -33,33 +33,49 @@
android:textAppearance="@style/BarChart.Text.HeaderTitle"/>
<LinearLayout
+ android:id="@+id/bar_views_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center|bottom">
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center|bottom">
- <com.android.settingslib.widget.BarView
- android:id="@+id/bar_view1"
- style="@style/BarViewStyle"
- settings:barColor="#FA7B17"/>
- <com.android.settingslib.widget.BarView
- android:id="@+id/bar_view2"
- style="@style/BarViewStyle"
- settings:barColor="#F439A0"/>
- <com.android.settingslib.widget.BarView
- android:id="@+id/bar_view3"
- style="@style/BarViewStyle"
- settings:barColor="#A142F4"/>
- <com.android.settingslib.widget.BarView
- android:id="@+id/bar_view4"
- style="@style/BarViewStyle"
- settings:barColor="#24C1E0"/>
+ <com.android.settingslib.widget.BarView
+ android:id="@+id/bar_view1"
+ style="@style/BarViewStyle"
+ settings:barColor="#FA7B17"/>
+ <com.android.settingslib.widget.BarView
+ android:id="@+id/bar_view2"
+ style="@style/BarViewStyle"
+ settings:barColor="#F439A0"/>
+ <com.android.settingslib.widget.BarView
+ android:id="@+id/bar_view3"
+ style="@style/BarViewStyle"
+ settings:barColor="#A142F4"/>
+ <com.android.settingslib.widget.BarView
+ android:id="@+id/bar_view4"
+ style="@style/BarViewStyle"
+ settings:barColor="#24C1E0"/>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/bar_chart_details"
+ style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:gravity="center"/>
</LinearLayout>
- <Button
- android:id="@+id/bar_chart_details"
- style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:gravity="center"/>
+ <TextView
+ android:id="@+id/empty_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/settings_bar_view_max_height"
+ android:gravity="center"
+ android:visibility="gone"
+ android:textAppearance="@style/BarChart.Text.Summary"/>
</LinearLayout>
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java
new file mode 100644
index 000000000000..eeaf2737a2fd
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java
@@ -0,0 +1,176 @@
+/*
+ * 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.widget;
+
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * BarChartInfo is responsible for storing information about {@link BarChartPreference}.
+ */
+public class BarChartInfo {
+ @StringRes
+ private final int mTitle;
+ @StringRes
+ private final int mDetails;
+ @StringRes
+ private final int mEmptyText;
+ private final View.OnClickListener mDetailsOnClickListener;
+
+ private BarViewInfo[] mBarViewInfos;
+
+ /**
+ * Gets the resource id for the title shown in {@link BarChartPreference}.
+ *
+ * @return the string resource id for title.
+ */
+ public int getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Gets the resource id for the details shown in {@link BarChartPreference}.
+ *
+ * @return the string resource id for details.
+ */
+ public int getDetails() {
+ return mDetails;
+ }
+
+ /**
+ * Gets the resource id for the empty text shown in {@link BarChartPreference} when there is no
+ * any bar view in {@link BarChartPreference}.
+ *
+ * @return the string resource id for empty text.
+ */
+ public int getEmptyText() {
+ return mEmptyText;
+ }
+
+ /**
+ * Gets the click listener for the details view.
+ *
+ * @return click listener for details view.
+ */
+ public View.OnClickListener getDetailsOnClickListener() {
+ return mDetailsOnClickListener;
+ }
+
+ /**
+ * Gets an array which contains up to four {@link BarViewInfo}
+ *
+ * @return an array holding the current all {@link BarViewInfo} state of the bar chart.
+ */
+ public BarViewInfo[] getBarViewInfos() {
+ return mBarViewInfos;
+ }
+
+ void setBarViewInfos(BarViewInfo[] barViewInfos) {
+ mBarViewInfos = barViewInfos;
+ }
+
+ private BarChartInfo(Builder builder) {
+ mTitle = builder.mTitle;
+ mDetails = builder.mDetails;
+ mEmptyText = builder.mEmptyText;
+ mDetailsOnClickListener = builder.mDetailsOnClickListener;
+
+ if (builder.mBarViewInfos != null) {
+ mBarViewInfos = builder.mBarViewInfos.stream().toArray(BarViewInfo[]::new);
+ }
+ }
+
+ /**
+ * Builder class for {@link BarChartInfo}
+ */
+ public static class Builder {
+ @StringRes
+ private int mTitle;
+ @StringRes
+ private int mDetails;
+ @StringRes
+ private int mEmptyText;
+ private View.OnClickListener mDetailsOnClickListener;
+ private List<BarViewInfo> mBarViewInfos;
+
+ /**
+ * Creates an instance of a {@link BarChartInfo} based on the current builder settings.
+ *
+ * @return The {@link BarChartInfo}.
+ */
+ public BarChartInfo build() {
+ if (mTitle == 0) {
+ throw new IllegalStateException("You must call Builder#setTitle() once.");
+ }
+ return new BarChartInfo(this);
+ }
+
+ /**
+ * Sets the string resource id for the title.
+ */
+ public Builder setTitle(@StringRes int title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets the string resource id for the details.
+ */
+ public Builder setDetails(@StringRes int details) {
+ mDetails = details;
+ return this;
+ }
+
+ /**
+ * Sets the string resource id for the empty text.
+ */
+ public Builder setEmptyText(@StringRes int emptyText) {
+ mEmptyText = emptyText;
+ return this;
+ }
+
+ /**
+ * Sets the click listener for details view.
+ */
+ public Builder setDetailsOnClickListener(
+ @Nullable View.OnClickListener clickListener) {
+ mDetailsOnClickListener = clickListener;
+ return this;
+ }
+
+ /**
+ * Adds a {@link BarViewInfo} for {@link BarChartPreference}.
+ * Maximum of 4 {@link BarViewInfo} can be added.
+ */
+ public Builder addBarViewInfo(@NonNull BarViewInfo barViewInfo) {
+ if (mBarViewInfos == null) {
+ mBarViewInfos = new ArrayList<>();
+ }
+ if (mBarViewInfos.size() >= BarChartPreference.MAXIMUM_BAR_VIEWS) {
+ throw new IllegalStateException("We only support up to four bar views");
+ }
+ mBarViewInfos.add(barViewInfo);
+ return this;
+ }
+ }
+}
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 305862af505b..eed66e94a9ef 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.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.
@@ -24,7 +24,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -41,31 +40,45 @@ import java.util.Arrays;
* android:key="bar_chart"/&gt;
* </pre>
*
- * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference defined
- * in the previous XML layout:
+ * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference
+ * defined in the previous XML layout:
*
* <pre>
- * BarViewInfo[] viewsInfo = new BarViewInfo [] {
- * new BarViewInfo(icon, 18, res of summary),
- * new BarViewInfo(icon, 25, res of summary),
- * new BarViewInfo(icon, 10, res of summary),
- * new BarViewInfo(icon, 3, res of summary),
- * };
+ * BarChartPreference preference = ((BarChartPreference) findPreference("bar_chart"));
+ *
+ * BarChartInfo info = new BarChartInfo.Builder()
+ * .setTitle(R.string.permission_bar_chart_title)
+ * .setDetails(R.string.permission_bar_chart_details)
+ * .setEmptyText(R.string.permission_bar_chart_empty_text)
+ * .addBarViewInfo(new barViewInfo(...))
+ * .addBarViewInfo(new barViewInfo(...))
+ * .addBarViewInfo(new barViewInfo(...))
+ * .addBarViewInfo(new barViewInfo(...))
+ * .setDetailsOnClickListener(v -> doSomething())
+ * .build();
+ *
+ * preference.initializeBarChart(info);
* </pre>
*
+ *
+ * <p>You also can update new information for bar views by
+ * {@link BarChartPreference#setBarViewInfos(BarViewInfo[])}
+ *
* <pre>
- * BarChartPreference preference = ((BarChartPreference) findPreference("bar_chart"));
+ * BarViewInfo[] barViewsInfo = new BarViewInfo [] {
+ * new BarViewInfo(...),
+ * new BarViewInfo(...),
+ * new BarViewInfo(...),
+ * new BarViewInfo(...),
+ * };
*
- * preference.setBarChartTitleRes(R.string.title_res);
- * preference.setBarChartDetailsRes(R.string.details_res);
- * preference.setBarChartDetailsClickListener(v -> doSomething());
- * preference.setAllBarViewsData(viewsInfo);
+ * preference.setBarViewInfos(barViewsInfo);
* </pre>
*/
public class BarChartPreference extends Preference {
+ static final int MAXIMUM_BAR_VIEWS = 4;
private static final String TAG = "BarChartPreference";
- private static final int MAXIMUM_BAR_VIEWS = 4;
private static final int[] BAR_VIEWS = {
R.id.bar_view1,
R.id.bar_view2,
@@ -74,12 +87,7 @@ public class BarChartPreference extends Preference {
};
private int mMaxBarHeight;
- @StringRes
- private int mTitleId;
- @StringRes
- private int mDetailsId;
- private BarViewInfo[] mBarViewsInfo;
- private View.OnClickListener mDetailsOnClickListener;
+ private BarChartInfo mBarChartInfo;
public BarChartPreference(Context context) {
super(context);
@@ -103,40 +111,26 @@ public class BarChartPreference extends Preference {
}
/**
- * Set the text resource for bar chart title.
- */
- public void setBarChartTitle(@StringRes int resId) {
- mTitleId = resId;
- notifyChanged();
- }
-
- /**
- * Set the text resource for bar chart details.
- */
- public void setBarChartDetails(@StringRes int resId) {
- mDetailsId = resId;
- notifyChanged();
- }
-
- /**
- * Register a callback to be invoked when bar chart details view is clicked.
+ * According to the information in {@link BarChartInfo} to initialize bar chart.
+ *
+ * @param barChartInfo The barChartInfo contains title, details, empty text, click listener
+ * attached on details view and four bar views.
*/
- public void setBarChartDetailsClickListener(@Nullable View.OnClickListener clickListener) {
- mDetailsOnClickListener = clickListener;
+ public void initializeBarChart(@NonNull BarChartInfo barChartInfo) {
+ mBarChartInfo = barChartInfo;
notifyChanged();
}
/**
- * Set all bar view information which you'd like to show in preference.
+ * Sets all bar view information which you'd like to show in preference.
*
- * @param barViewsInfo the barViewsInfo contain at least one {@link BarViewInfo}.
+ * @param barViewInfos the barViewInfos contain at least one {@link BarViewInfo}.
*/
- public void setAllBarViewsInfo(@NonNull BarViewInfo[] barViewsInfo) {
- mBarViewsInfo = barViewsInfo;
- // Do a sort in descending order, the first element would have max {@link
- // BarViewInfo#mBarNumber}
- Arrays.sort(mBarViewsInfo);
- calculateAllBarViewHeights();
+ public void setBarViewInfos(@Nullable BarViewInfo[] barViewInfos) {
+ if (barViewInfos != null && barViewInfos.length > MAXIMUM_BAR_VIEWS) {
+ throw new IllegalStateException("We only support up to four bar views");
+ }
+ mBarChartInfo.setBarViewInfos(barViewInfos);
notifyChanged();
}
@@ -146,7 +140,17 @@ public class BarChartPreference extends Preference {
holder.setDividerAllowedAbove(true);
holder.setDividerAllowedBelow(true);
+ // We must show title of bar chart.
bindChartTitleView(holder);
+
+ final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+ // If there is no any bar view, we just show an empty text.
+ if (barViewInfos == null || barViewInfos.length == 0) {
+ setEmptyViewVisible(holder, true /* visible */);
+ return;
+ }
+ setEmptyViewVisible(holder, false /* visible */);
+
bindChartDetailsView(holder);
updateBarChart(holder);
}
@@ -160,42 +164,68 @@ public class BarChartPreference extends Preference {
private void bindChartTitleView(PreferenceViewHolder holder) {
final TextView titleView = (TextView) holder.findViewById(R.id.bar_chart_title);
- titleView.setText(mTitleId);
+ titleView.setText(mBarChartInfo.getTitle());
}
private void bindChartDetailsView(PreferenceViewHolder holder) {
final Button detailsView = (Button) holder.findViewById(R.id.bar_chart_details);
- if (mDetailsId == 0) {
+ final int details = mBarChartInfo.getDetails();
+ if (details == 0) {
detailsView.setVisibility(View.GONE);
} else {
- detailsView.setText(mDetailsId);
- detailsView.setOnClickListener(mDetailsOnClickListener);
+ detailsView.setVisibility(View.VISIBLE);
+ detailsView.setText(details);
+ detailsView.setOnClickListener(mBarChartInfo.getDetailsOnClickListener());
}
}
private void updateBarChart(PreferenceViewHolder holder) {
+ normalizeBarViewHeights();
+
+ final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+
for (int index = 0; index < MAXIMUM_BAR_VIEWS; index++) {
final BarView barView = (BarView) holder.findViewById(BAR_VIEWS[index]);
- // If there is no bar views data can be shown.
- if (mBarViewsInfo == null || index >= mBarViewsInfo.length) {
+ // If there is no bar view info can be shown.
+ if (barViewInfos == null || index >= barViewInfos.length) {
barView.setVisibility(View.GONE);
continue;
}
barView.setVisibility(View.VISIBLE);
- barView.updateView(mBarViewsInfo[index]);
+ barView.updateView(barViewInfos[index]);
}
}
- private void calculateAllBarViewHeights() {
+ private void normalizeBarViewHeights() {
+ final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+ // If there is no any bar view info, we don't need to calculate the height of all bar views.
+ if (barViewInfos == null || barViewInfos.length == 0) {
+ return;
+ }
+ // Do a sort in descending order, the first element would have max {@link
+ // BarViewInfo#mHeight}
+ Arrays.sort(barViewInfos);
// Since we sorted this array in advance, the first element must have the max {@link
// BarViewInfo#mHeight}.
- final int maxBarHeight = mBarViewsInfo[0].getHeight();
+ final int maxBarHeight = barViewInfos[0].getHeight();
// If the max number of bar view is zero, then we don't calculate the unit for bar height.
final int unit = maxBarHeight == 0 ? 0 : mMaxBarHeight / maxBarHeight;
- for (BarViewInfo barView : mBarViewsInfo) {
+ for (BarViewInfo barView : barViewInfos) {
barView.setNormalizedHeight(barView.getHeight() * unit);
}
}
+
+ private void setEmptyViewVisible(PreferenceViewHolder holder, boolean visible) {
+ final View barViewsContainer = holder.findViewById(R.id.bar_views_container);
+ final TextView emptyView = (TextView) holder.findViewById(R.id.empty_view);
+ final int emptyTextRes = mBarChartInfo.getEmptyText();
+
+ if (emptyTextRes != 0) {
+ emptyView.setText(emptyTextRes);
+ }
+ emptyView.setVisibility(visible ? View.VISIBLE : View.GONE);
+ barViewsContainer.setVisibility(visible ? View.GONE : View.VISIBLE);
+ }
}
diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
index cbebbb32dc89..d6dc211ad8c4 100644
--- a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
+++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
@@ -18,12 +18,11 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack">
<item>
- <shape
- android:tint="?android:attr/colorForeground">
+ <shape>
<corners
android:radius="20dp"/>
<solid
- android:color="@android:color/transparent"/>
+ android:color="?android:attr/colorPrimary"/>
<stroke
android:color="#1f000000"
android:width="1dp"/>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 842779d494cd..7dcc3acb1dae 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1138,7 +1138,7 @@
<string name="notice_header" translatable="false"></string>
<!-- UI debug setting: opt in to use updated graphics driver? [CHAR LIMIT=100] -->
- <string name="updated_gfx_driver_dev_opt_in_app_summary">Opt in app to use updated graphcis driver in developement</string>
+ <string name="gup_dev_opt_in_app_summary">Opt in app to use Game Update Package in developement</string>
<!-- Name of the phone device [CHAR LIMIT=NONE] -->
<string name="media_transfer_phone_device_name">Phone speaker</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
index 2387b01d341d..5e5c22a403d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
@@ -16,8 +16,8 @@
package com.android.settingslib.applications;
import android.content.Context;
+import android.permission.PermissionControllerManager;
import android.permission.RuntimePermissionPresentationInfo;
-import android.permission.RuntimePermissionPresenter;
import java.text.Collator;
import java.util.ArrayList;
@@ -28,9 +28,9 @@ public class PermissionsSummaryHelper {
public static void getPermissionSummary(Context context, String pkg,
final PermissionsResultCallback callback) {
- final RuntimePermissionPresenter presenter =
- RuntimePermissionPresenter.getInstance(context);
- presenter.getAppPermissions(pkg, permissions -> {
+ final PermissionControllerManager permController =
+ context.getSystemService(PermissionControllerManager.class);
+ permController.getAppPermissions(pkg, permissions -> {
final int permissionCount = permissions.size();
int grantedStandardCount = 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 58feef55bd29..24d7011d9a35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -35,7 +35,6 @@ import java.util.List;
public class A2dpProfile implements LocalBluetoothProfile {
private static final String TAG = "A2dpProfile";
- private static boolean V = false;
private Context mContext;
@@ -60,7 +59,6 @@ public class A2dpProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothA2dp) proxy;
// We just bound to the service, so refresh the UI for any connected A2DP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -79,7 +77,6 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
@@ -302,7 +299,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 988062de0a37..873dd1a643a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -55,7 +55,6 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected");
mService = (BluetoothA2dpSink) proxy;
// We just bound to the service, so refresh the UI for any connected A2DP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -74,7 +73,6 @@ final class A2dpSinkProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected");
mIsProfileReady=false;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 177ba00c8a31..4f18d450462d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -484,6 +484,10 @@ public class BluetoothEventManager {
return;
}
final CachedBluetoothDevice activeDevice = mDeviceManager.findDevice(device);
+ if (activeDevice == null) {
+ Log.w(TAG, "AclStateChangedHandler: activeDevice is null");
+ return;
+ }
final int state;
switch (action) {
case BluetoothDevice.ACTION_ACL_CONNECTED:
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 62507f58426f..6b6df9b928e5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -58,7 +58,6 @@ public class HeadsetProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothHeadset) proxy;
// We just bound to the service, so refresh the UI for any connected HFP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@ public class HeadsetProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG,"Bluetooth service disconnected");
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index adb5ab34b5c1..577d98d93405 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -51,7 +51,6 @@ public class HearingAidProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothHearingAid) proxy;
// We just bound to the service, so refresh the UI for any connected HearingAid devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -77,7 +76,6 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
@@ -234,7 +232,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4879144a5994..c6bb2b304d6c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -59,7 +59,6 @@ final class HfpClientProfile implements LocalBluetoothProfile {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected");
mService = (BluetoothHeadsetClient) proxy;
// We just bound to the service, so refresh the UI for any connected HFP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@ final class HfpClientProfile implements LocalBluetoothProfile {
@Override
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected");
mIsProfileReady=false;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 61e5b6b3e125..4dc050c6d5e3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -58,7 +58,6 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected :-), profile:" + profile);
mService = (BluetoothHidDevice) proxy;
// We just bound to the service, so refresh the UI for any connected HID devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -78,7 +77,6 @@ public class HidDeviceProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 75d16db13efe..ca840d9a8ba4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -33,7 +33,6 @@ import java.util.List;
*/
public class HidProfile implements LocalBluetoothProfile {
private static final String TAG = "HidProfile";
- private static boolean V = true;
private BluetoothHidHost mService;
private boolean mIsProfileReady;
@@ -51,7 +50,6 @@ public class HidProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothHidHost) proxy;
// We just bound to the service, so refresh the UI for any connected HID devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -70,7 +68,6 @@ public class HidProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
@@ -186,7 +183,7 @@ public class HidProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_HOST,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 1e22f440b5f8..6acdcac86d92 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -59,7 +59,6 @@ public final class MapClientProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothMapClient) proxy;
// We just bound to the service, so refresh the UI for any connected MAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -81,7 +80,6 @@ public final class MapClientProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 758202412c93..28975d4b94c2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -58,7 +58,6 @@ public class MapProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected");
mService = (BluetoothMap) proxy;
// We just bound to the service, so refresh the UI for any connected MAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@ public class MapProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected");
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 7b811624a6f3..2d0a0902de24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -34,7 +34,6 @@ import java.util.List;
*/
public class PanProfile implements LocalBluetoothProfile {
private static final String TAG = "PanProfile";
- private static boolean V = true;
private BluetoothPan mService;
private boolean mIsProfileReady;
@@ -53,13 +52,11 @@ public class PanProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothPan) proxy;
mIsProfileReady=true;
}
public void onServiceDisconnected(int profile) {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
@@ -173,7 +170,7 @@ public class PanProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 1f15601f2756..46723937a941 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -55,7 +55,6 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothPbapClient) proxy;
// We just bound to the service, so refresh the UI for any connected PBAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -74,7 +73,6 @@ public final class PbapClientProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mIsProfileReady = false;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index adef0841cb2a..1b3c453be4ed 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -33,7 +33,6 @@ import com.android.settingslib.R;
*/
public class PbapServerProfile implements LocalBluetoothProfile {
private static final String TAG = "PbapServerProfile";
- private static boolean V = true;
private BluetoothPbap mService;
private boolean mIsProfileReady;
@@ -56,13 +55,11 @@ public class PbapServerProfile implements LocalBluetoothProfile {
implements BluetoothPbap.ServiceListener {
public void onServiceConnected(BluetoothPbap proxy) {
- if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothPbap) proxy;
mIsProfileReady=true;
}
public void onServiceDisconnected() {
- if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
@@ -142,7 +139,7 @@ public class PbapServerProfile implements LocalBluetoothProfile {
}
protected void finalize() {
- if (V) Log.d(TAG, "finalize()");
+ Log.d(TAG, "finalize()");
if (mService != null) {
try {
mService.close();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index b4acc4810faf..ea2ebde3ff4c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -57,7 +57,6 @@ final class SapProfile implements LocalBluetoothProfile {
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
- Log.d(TAG, "Bluetooth service connected, profile:" + profile);
mService = (BluetoothSap) proxy;
// We just bound to the service, so refresh the UI for any connected SAP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -79,7 +78,6 @@ final class SapProfile implements LocalBluetoothProfile {
}
public void onServiceDisconnected(int profile) {
- Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
mProfileManager.callServiceDisconnectedListeners();
mIsProfileReady=false;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 9af06702a696..4ac3ce436f82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -31,6 +31,7 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import java.time.Clock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -56,11 +57,18 @@ public class RecentLocationAccesses {
private final PackageManager mPackageManager;
private final Context mContext;
private final IconDrawableFactory mDrawableFactory;
+ private final Clock mClock;
public RecentLocationAccesses(Context context) {
+ this(context, Clock.systemDefaultZone());
+ }
+
+ @VisibleForTesting
+ RecentLocationAccesses(Context context, Clock clock) {
mContext = context;
mPackageManager = context.getPackageManager();
mDrawableFactory = IconDrawableFactory.newInstance(context);
+ mClock = clock;
}
/**
@@ -77,7 +85,7 @@ public class RecentLocationAccesses {
// Process the AppOps list and generate a preference list.
ArrayList<Access> accesses = new ArrayList<>(appOpsCount);
- final long now = System.currentTimeMillis();
+ final long now = mClock.millis();
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final List<UserHandle> profiles = um.getUserProfiles();
@@ -175,7 +183,7 @@ public class RecentLocationAccesses {
public final CharSequence contentDescription;
public final long accessFinishTime;
- private Access(String packageName, UserHandle userHandle, Drawable icon,
+ public Access(String packageName, UserHandle userHandle, Drawable icon,
CharSequence label, CharSequence contentDescription,
long accessFinishTime) {
this.packageName = packageName;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 0dcdaed67cd6..2c70cbbe6ecb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -181,4 +181,17 @@ public class BluetoothEventManagerTest {
verify(mBluetoothCallback, never()).onAclConnectionStateChanged(mCachedBluetoothDevice,
BluetoothAdapter.STATE_CONNECTED);
}
+
+ @Test
+ public void dispatchAclConnectionStateChanged_findDeviceReturnNull_shouldNotDispatchCallback() {
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(null);
+ mBluetoothEventManager.registerCallback(mBluetoothCallback);
+ mIntent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mBluetoothCallback, never()).onAclConnectionStateChanged(mCachedBluetoothDevice,
+ BluetoothAdapter.STATE_CONNECTED);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
new file mode 100644
index 000000000000..d5b89ca719ad
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -0,0 +1,162 @@
+package com.android.settingslib.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.PackageOps;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.time.Clock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(RobolectricTestRunner.class)
+public class RecentLocationAccessesTest {
+
+ private static final int TEST_UID = 1234;
+ private static final long NOW = 1_000_000_000; // Approximately 9/8/2001
+ private static final long ONE_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(1);
+ private static final long TWENTY_THREE_HOURS_AGO = NOW - TimeUnit.HOURS.toMillis(23);
+ private static final long TWO_DAYS_AGO = NOW - TimeUnit.DAYS.toMillis(2);
+ private static final String[] TEST_PACKAGE_NAMES =
+ {"package_1MinAgo", "package_14MinAgo", "package_20MinAgo"};
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private Clock mClock;
+ private Context mContext;
+ private int mTestUserId;
+ private RecentLocationAccesses mRecentLocationAccesses;
+
+ @Before
+ public void setUp() throws NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mPackageManager.getApplicationLabel(isA(ApplicationInfo.class)))
+ .thenReturn("testApplicationLabel");
+ when(mPackageManager.getUserBadgedLabel(isA(CharSequence.class), isA(UserHandle.class)))
+ .thenReturn("testUserBadgedLabel");
+ mTestUserId = UserHandle.getUserId(TEST_UID);
+ when(mUserManager.getUserProfiles())
+ .thenReturn(Collections.singletonList(new UserHandle(mTestUserId)));
+
+ long[] testRequestTime = {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO};
+ List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
+ when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+ appOps);
+ mockTestApplicationInfos(mTestUserId, TEST_PACKAGE_NAMES);
+
+ when(mClock.millis()).thenReturn(NOW);
+ mRecentLocationAccesses = new RecentLocationAccesses(mContext, mClock);
+ }
+
+ @Test
+ public void testGetAppList_shouldFilterRecentAccesses() {
+ List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+ // Only two of the apps have requested location within 15 min.
+ assertThat(requests).hasSize(2);
+ // Make sure apps are ordered by recency
+ assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+ assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+ assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+ assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+ }
+
+ @Test
+ public void testGetAppList_shouldNotShowAndroidOS() throws NameNotFoundException {
+ // Add android OS to the list of apps.
+ PackageOps androidSystemPackageOps =
+ createPackageOps(
+ RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME,
+ Process.SYSTEM_UID,
+ AppOpsManager.OP_FINE_LOCATION,
+ ONE_MIN_AGO);
+ long[] testRequestTime =
+ {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO, ONE_MIN_AGO};
+ List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
+ appOps.add(androidSystemPackageOps);
+ when(mAppOpsManager.getPackagesForOps(RecentLocationAccesses.LOCATION_OPS)).thenReturn(
+ appOps);
+ mockTestApplicationInfos(
+ Process.SYSTEM_UID, RecentLocationAccesses.ANDROID_SYSTEM_PACKAGE_NAME);
+
+ List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
+ // Android OS shouldn't show up in the list of apps.
+ assertThat(requests).hasSize(2);
+ // Make sure apps are ordered by recency
+ assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
+ assertThat(requests.get(0).accessFinishTime).isEqualTo(ONE_MIN_AGO);
+ assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
+ assertThat(requests.get(1).accessFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO);
+ }
+
+ private void mockTestApplicationInfos(int userId, String... packageNameList)
+ throws NameNotFoundException {
+ for (String packageName : packageNameList) {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = packageName;
+ when(mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userId)).thenReturn(appInfo);
+ }
+ }
+
+ private List<PackageOps> createTestPackageOpsList(String[] packageNameList, long[] time) {
+ List<PackageOps> packageOpsList = new ArrayList<>();
+ for (int i = 0; i < packageNameList.length; i++) {
+ PackageOps packageOps = createPackageOps(
+ packageNameList[i],
+ TEST_UID,
+ AppOpsManager.OP_FINE_LOCATION,
+ time[i]);
+ packageOpsList.add(packageOps);
+ }
+ return packageOpsList;
+ }
+
+ private PackageOps createPackageOps(String packageName, int uid, int op, long time) {
+ return new PackageOps(
+ packageName,
+ uid,
+ Collections.singletonList(createOpEntryWithTime(op, time)));
+ }
+
+ private OpEntry createOpEntryWithTime(int op, long time) {
+ final long[] times = new long[AppOpsManager._NUM_UID_STATE];
+ // Slot for background access timestamp.
+ times[AppOpsManager.UID_STATE_LAST_NON_RESTRICTED + 1] = time;
+ final long[] rejectTimes = new long[AppOpsManager._NUM_UID_STATE];
+ return new OpEntry(op, AppOpsManager.MODE_ALLOWED, times, rejectTimes, 0 /* duration */,
+ 0 /* proxyUid */, "" /* proxyPackage */);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
new file mode 100644
index 000000000000..29d57b7bbeef
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.View;
+
+import androidx.annotation.StringRes;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BarChartInfoTest {
+
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+ @StringRes
+ private final int mTitle = 0x11111111;
+ @StringRes
+ private final int mDetails = 0x22222222;
+ @StringRes
+ private final int mEmptyText = 0x33333333;
+ private final View.OnClickListener mClickListener = v -> {
+ };
+
+ @Test
+ public void builder_shouldSetFieldsInTheInfo() {
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(mTitle)
+ .setDetails(mDetails)
+ .setEmptyText(mEmptyText)
+ .setDetailsOnClickListener(mClickListener)
+ .build();
+ assertThat(barChartInfo.getTitle()).isEqualTo(mTitle);
+ assertThat(barChartInfo.getDetails()).isEqualTo(mDetails);
+ assertThat(barChartInfo.getEmptyText()).isEqualTo(mEmptyText);
+ assertThat(barChartInfo.getDetailsOnClickListener()).isEqualTo(mClickListener);
+ }
+
+ @Test
+ public void builder_noTitle_shouldThrowIllegalStateException() {
+ thrown.expect(IllegalStateException.class);
+
+ new BarChartInfo.Builder()
+ .setDetails(mDetails)
+ .setEmptyText(mEmptyText)
+ .setDetailsOnClickListener(mClickListener)
+ .build();
+ }
+
+ @Test
+ public void addBarViewInfo_oneBarViewInfo_shouldSetOneBarViewInfo() {
+ final BarViewInfo barViewInfo = new BarViewInfo(
+ null /* icon */,
+ 50,
+ mTitle);
+
+ final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
+ .setTitle(mTitle)
+ .setDetails(mDetails)
+ .setEmptyText(mEmptyText)
+ .setDetailsOnClickListener(mClickListener)
+ .addBarViewInfo(barViewInfo)
+ .build();
+
+ assertThat(mBarChartInfo.getBarViewInfos().length).isEqualTo(1);
+ assertThat(mBarChartInfo.getBarViewInfos()[0]).isEqualTo(barViewInfo);
+ }
+
+ @Test
+ public void addBarViewInfo_maxNumberOfInfoAllowed_shouldSetMaxBarViewInfos() {
+ final BarViewInfo barViewInfo = new BarViewInfo(
+ null /* icon */,
+ 50,
+ mTitle);
+ final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
+ .setTitle(mTitle)
+ .setDetails(mDetails)
+ .setEmptyText(mEmptyText)
+ .setDetailsOnClickListener(mClickListener)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .build();
+
+ assertThat(mBarChartInfo.getBarViewInfos().length).isEqualTo(4);
+ }
+
+ @Test
+ public void addBarViewInfo_moreInfosThanMaxAllowed_shouldThrowIllegalStateException() {
+ thrown.expect(IllegalStateException.class);
+
+ final BarViewInfo barViewInfo = new BarViewInfo(
+ null /* icon */,
+ 50,
+ mTitle);
+ new BarChartInfo.Builder()
+ .setTitle(mTitle)
+ .setDetails(mDetails)
+ .setEmptyText(mEmptyText)
+ .setDetailsOnClickListener(mClickListener)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .addBarViewInfo(barViewInfo)
+ .build();
+ }
+}
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 375b45cf46d0..cf6137d47bb0 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
@@ -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.
@@ -26,7 +26,9 @@ import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -34,6 +36,9 @@ import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BarChartPreferenceTest {
+ @Rule
+ public final ExpectedException thrown = ExpectedException.none();
+
private Context mContext;
private View mBarChartView;
private Drawable mIcon;
@@ -44,6 +49,7 @@ public class BarChartPreferenceTest {
private TextView mDetailsView;
private PreferenceViewHolder mHolder;
private BarChartPreference mPreference;
+ private BarChartInfo mBarChartInfo;
@Before
public void setUp() {
@@ -51,21 +57,31 @@ public class BarChartPreferenceTest {
mBarChartView = View.inflate(mContext, R.layout.settings_bar_chart, null /* parent */);
mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
mPreference = new BarChartPreference(mContext, null /* attrs */);
- mPreference.setBarChartTitle(R.string.debug_app);
mIcon = mContext.getDrawable(R.drawable.ic_menu);
- mBarView1 = (BarView) mBarChartView.findViewById(R.id.bar_view1);
- mBarView2 = (BarView) mBarChartView.findViewById(R.id.bar_view2);
- mBarView3 = (BarView) mBarChartView.findViewById(R.id.bar_view3);
- mBarView4 = (BarView) mBarChartView.findViewById(R.id.bar_view4);
- mDetailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
+ mBarView1 = mBarChartView.findViewById(R.id.bar_view1);
+ mBarView2 = mBarChartView.findViewById(R.id.bar_view2);
+ mBarView3 = mBarChartView.findViewById(R.id.bar_view3);
+ mBarView4 = mBarChartView.findViewById(R.id.bar_view4);
+ mDetailsView = mBarChartView.findViewById(R.id.bar_chart_details);
+
+ mBarChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .setDetails(R.string.debug_app)
+ .setEmptyText(R.string.debug_app)
+ .setDetailsOnClickListener(v -> {
+ })
+ .build();
}
@Test
- public void setBarChartTitleRes_setTitleRes_showInBarChartTitle() {
- final TextView titleView = (TextView) mBarChartView.findViewById(R.id.bar_chart_title);
+ public void initializeBarChart_titleSet_shouldSetTitleInChartView() {
+ final TextView titleView = mBarChartView.findViewById(R.id.bar_chart_title);
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .build();
- mPreference.setBarChartTitle(R.string.debug_app);
+ mPreference.initializeBarChart(barChartInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(titleView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -73,16 +89,33 @@ public class BarChartPreferenceTest {
}
@Test
- public void onBindViewHolder_notSetDetailsRes_barChartDetailsViewIsGone() {
- // We don't call BarChartPreference#setBarChartDetails
+ public void initializeBarChart_noBarViewSet_shouldShowTitleAndEmptyView() {
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .setEmptyText(R.string.debug_app)
+ .build();
+
+ mPreference.initializeBarChart(barChartInfo);
+ // We don't add any bar view yet.
mPreference.onBindViewHolder(mHolder);
- assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mBarChartView.findViewById(R.id.bar_chart_title).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mBarChartView.findViewById(R.id.empty_view).getVisibility())
+ .isEqualTo(View.VISIBLE);
+ assertThat(mBarChartView.findViewById(R.id.bar_views_container).getVisibility())
+ .isEqualTo(View.GONE);
}
@Test
- public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
- mPreference.setBarChartDetails(R.string.debug_app);
+ public void initializeBarChart_detailsSet_shouldShowBarChartDetailsView() {
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .setDetails(R.string.debug_app)
+ .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+ .build();
+
+ mPreference.initializeBarChart(barChartInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -90,10 +123,30 @@ public class BarChartPreferenceTest {
}
@Test
- public void setBarChartDetailsClickListener_setClickListener_detailsViewAttachClickListener() {
- mPreference.setBarChartDetails(R.string.debug_app);
- mPreference.setBarChartDetailsClickListener(v -> {
- });
+ public void initializeBarChart_detailsNotSet_shouldHideBarChartDetailsView() {
+ // We don't call BarChartInfo.Builder#setDetails yet.
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+ .build();
+
+ mPreference.initializeBarChart(barChartInfo);
+ mPreference.onBindViewHolder(mHolder);
+
+ assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void initializeBarChart_clickListenerSet_shouldSetClickListenerOnDetailsView() {
+ final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+ .setTitle(R.string.debug_app)
+ .setDetails(R.string.debug_app)
+ .setDetailsOnClickListener(v -> {
+ })
+ .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+ .build();
+
+ mPreference.initializeBarChart(barChartInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -101,12 +154,13 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setOneBarViewInfo_showOneBarView() {
+ public void setBarViewInfos_oneBarViewInfoSet_shouldShowOneBarView() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -118,13 +172,14 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setTwoBarViewsInfo_showTwoBarViews() {
+ public void setBarViewInfos_twoBarViewInfosSet_shouldShowTwoBarViews() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -137,14 +192,15 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setThreeBarViewsInfo_showThreeBarViews() {
+ public void setBarViewInfos_threeBarViewInfosSet_shouldShowThreeBarViews() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app)
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -158,7 +214,7 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setFourBarViewsInfo_showFourBarViews() {
+ public void setBarViewInfos_fourBarViewInfosSet_shouldShowFourBarViews() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
@@ -166,7 +222,8 @@ public class BarChartPreferenceTest {
new BarViewInfo(mIcon, 2 /* barNumber */, R.string.debug_app),
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -180,7 +237,22 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setFourBarViewsInfo_barViewWasSortedInDescending() {
+ public void setBarViewInfos_moreInfosThanMaxAllowed_shouldThrowIllegalStateException() {
+ thrown.expect(IllegalStateException.class);
+
+ final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+ new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app),
+ new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app),
+ new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app),
+ new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+ new BarViewInfo(mIcon, 70 /* barNumber */, R.string.debug_app),
+ };
+
+ mPreference.setBarViewInfos(barViewsInfo);
+ }
+
+ @Test
+ public void setBarViewInfos_barViewInfosSet_shouldBeSortedInDescending() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app),
new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app),
@@ -188,7 +260,8 @@ public class BarChartPreferenceTest {
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -202,12 +275,13 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setValidSummaryRes_barViewShouldShowSummary() {
+ public void setBarViewInfos_validBarViewSummarySet_barViewShouldShowSummary() {
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -215,13 +289,14 @@ public class BarChartPreferenceTest {
}
@Test
- public void setAllBarViewsInfo_setClickListenerForBarView_barViewAttachClickListener() {
+ public void setBarViewInfos_clickListenerForBarViewSet_barViewShouldHaveClickListener() {
final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app);
viewInfo.setClickListener(v -> {
});
final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
- mPreference.setAllBarViewsInfo(barViewsInfo);
+ mPreference.initializeBarChart(mBarChartInfo);
+ mPreference.setBarViewInfos(barViewsInfo);
mPreference.onBindViewHolder(mHolder);
assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index f2b2719f2ee6..d0ffe7ae8c7e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -242,7 +242,7 @@ public final class DeviceConfigService extends Binder {
Bundle args = new Bundle();
args.putInt(Settings.CALL_METHOD_USER_KEY,
ActivityManager.getService().getCurrentUser().id);
- Bundle b = provider.call(resolveCallingPackage(),
+ Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
} catch (RemoteException e) {
@@ -261,7 +261,7 @@ public final class DeviceConfigService extends Binder {
if (namespace != null) {
args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
}
- Bundle b = provider.call(resolveCallingPackage(),
+ Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
Settings.CALL_METHOD_LIST_CONFIG, null, args);
if (b != null) {
Map<String, String> flagsToValues =
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e3d3d81704a8..526efcb35262 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -705,8 +705,11 @@ class SettingsProtoDumpUtil {
Settings.Global.GPU_DEBUG_LAYERS_GLES,
GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES);
dumpSetting(s, p,
- Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
- GlobalSettingsProto.Gpu.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
+ Settings.Global.GUP_DEV_OPT_IN_APPS,
+ GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS);
+ dumpSetting(s, p,
+ Settings.Global.GUP_BLACK_LIST,
+ GlobalSettingsProto.Gpu.GUP_BLACK_LIST);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ce529a085e77..bce559396ddd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1097,7 +1097,7 @@ public class SettingsProvider extends ContentProvider {
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
UserHandle.USER_SYSTEM, name, value, null, makeDefault, true,
- getCallingPackage(), false, null);
+ resolveCallingPackage(), false, null);
}
case MUTATION_OPERATION_DELETE: {
@@ -1107,7 +1107,7 @@ public class SettingsProvider extends ContentProvider {
case MUTATION_OPERATION_RESET: {
mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM, getCallingPackage(), mode, null, prefix);
+ UserHandle.USER_SYSTEM, resolveCallingPackage(), mode, null, prefix);
} return true;
}
}
@@ -2247,6 +2247,22 @@ public class SettingsProvider extends ContentProvider {
return !(TextUtils.isEmpty(key) || SettingsState.isBinary(key));
}
+ private String resolveCallingPackage() {
+ switch (Binder.getCallingUid()) {
+ case Process.ROOT_UID: {
+ return "root";
+ }
+
+ case Process.SHELL_UID: {
+ return "com.android.shell";
+ }
+
+ default: {
+ return getCallingPackage();
+ }
+ }
+ }
+
private static final class Arguments {
private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
@@ -4125,10 +4141,12 @@ public class SettingsProvider extends ContentProvider {
Secure.CHARGING_SOUNDS_ENABLED);
if (!globalChargingSoundEnabled.isNull()) {
- secureSettings.insertSettingLocked(
- Secure.CHARGING_SOUNDS_ENABLED,
- globalChargingSoundEnabled.getValue(), null, false,
- SettingsState.SYSTEM_PACKAGE_NAME);
+ if (secureChargingSoundsEnabled.isNull()) {
+ secureSettings.insertSettingLocked(
+ Secure.CHARGING_SOUNDS_ENABLED,
+ globalChargingSoundEnabled.getValue(), null, false,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
// set global charging_sounds_enabled setting to null since it's deprecated
globalSettings.insertSettingLocked(
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index 0d681ed0f37a..ac97adb2c5c5 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \
../src/com/android/providers/settings/SettingsState.java \
../src/com/android/providers/settings/SettingsHelper.java
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
LOCAL_JAVA_LIBRARIES := android.test.base
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 71e0b153daa9..87a4f603f70b 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -29,7 +29,7 @@
</application>
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.providers.setting.test"
android:label="Settings Provider Tests" />
diff --git a/packages/SettingsProvider/test/AndroidTest.xml b/packages/SettingsProvider/test/AndroidTest.xml
index 46b8f94f23a3..9d2352670ddd 100644
--- a/packages/SettingsProvider/test/AndroidTest.xml
+++ b/packages/SettingsProvider/test/AndroidTest.xml
@@ -22,7 +22,7 @@
<option name="test-tag" value="SettingsProviderTest" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.providers.setting.test" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index ab23af39b98f..68efa6779f04 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -25,9 +25,12 @@ import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import libcore.io.Streams;
+
import org.junit.runner.RunWith;
import java.io.FileInputStream;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
index 5587cba59150..df4656a6deeb 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -24,8 +24,9 @@ import android.content.ContentResolver;
import android.os.Bundle;
import android.provider.DeviceConfig;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
import libcore.io.Streams;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
index d8ee9b64c7d9..863b0352913a 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/InstallNonMarketAppsDeprecationTest.java
@@ -26,10 +26,11 @@ import android.os.Process;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
index 10749571b623..54f8688bf5d6 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -24,8 +24,10 @@ import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
index 6fa014d4bef7..d112facc2b0e 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperTest.java
@@ -17,19 +17,10 @@
package com.android.providers.settings;
import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertSame;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.fail;
-
-import com.android.internal.app.LocalePicker;
-import com.android.providers.settings.SettingsHelper;
import android.os.LocaleList;
-import android.support.test.runner.AndroidJUnit4;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8cfc2a6b158d..bff2c844bb48 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -82,6 +82,7 @@
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
+ <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml b/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
deleted file mode 100644
index 2d779499f6e6..000000000000
--- a/packages/SystemUI/legacy/recents/res/drawable/ic_lock_to_app_24dp.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="@color/recents_task_view_lock_to_app_button_color"
- android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
-</vector>
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
deleted file mode 100644
index 5f9341c0d151..000000000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_freeform_workspace_bg.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners android:topLeftRadius="@dimen/recents_task_view_rounded_corners_radius"
- android:topRightRadius="@dimen/recents_task_view_rounded_corners_radius"/>
- <solid android:color="#00000000" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
deleted file mode 100644
index 9a060b4a3d39..000000000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_dark.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <group
- android:translateX="-286.000000"
- android:translateY="-602.000000">
- <group
- android:translateX="109.000000"
- android:translateY="514.000000">
- <group
- android:translateX="178.000000"
- android:translateY="89.000000">
- <path
- android:strokeColor="@color/recents_task_bar_dark_icon_color"
- android:strokeWidth="2"
- android:pathData="M10,12 L10,3 L19,3 L19,5 L19,11 L19,12 L10,12 Z" />
- <path
- android:strokeColor="@color/recents_task_bar_dark_icon_color"
- android:strokeWidth="2"
- android:pathData="M15,17 L5,17 L5,7 L5,17 Z" />
- </group>
- </group>
- </group>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml b/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
deleted file mode 100644
index b8acedb3c2f7..000000000000
--- a/packages/SystemUI/legacy/recents/res/drawable/recents_move_task_freeform_light.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <group
- android:translateX="-286.000000"
- android:translateY="-602.000000">
- <group
- android:translateX="109.000000"
- android:translateY="514.000000">
- <group
- android:translateX="178.000000"
- android:translateY="89.000000">
- <path
- android:strokeColor="@color/recents_task_bar_light_icon_color"
- android:strokeWidth="2"
- android:pathData="M10,12 L10,3 L19,3 L19,5 L19,11 L19,12 L10,12 Z" />
- <path
- android:strokeColor="@color/recents_task_bar_light_icon_color"
- android:strokeWidth="2"
- android:pathData="M15,17 L5,17 L5,7 L5,17 Z" />
- </group>
- </group>
- </group>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 4891e5006279..5317a6df53e8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -32,10 +32,11 @@ public interface ActivityStarter {
void startPendingIntentDismissingKeyguard(PendingIntent intent);
/**
- * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but
- * allow you to specify the callback that is executed after the intent is sent.
+ * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but allows
+ * you to specify the callback that is executed on the UI thread after the intent is sent.
*/
- void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentCallback);
+ void startPendingIntentDismissingKeyguard(PendingIntent intent,
+ Runnable intentSentUiThreadCallback);
void startActivity(Intent intent, boolean dismissShade);
void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
void startActivity(Intent intent, boolean dismissShade, Callback callback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index 0823db9aa7a9..c7bc858c8266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -1,62 +1,80 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.policy;
+package com.android.systemui.plugins;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.View;
import android.widget.ImageView;
-import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
* Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area and dark
- * intensity
+ * intensity. Accessible through {@link PluginDependency}
*/
-public interface DarkIconDispatcher extends Dumpable {
+@ProvidesInterface(version = DarkIconDispatcher.VERSION)
+@DependsOn(target = DarkReceiver.class)
+public interface DarkIconDispatcher {
+ int VERSION = 1;
+ /**
+ * Sets the dark area so {@link #applyDark} only affects the icons in the specified area.
+ *
+ * @param r the area in which icons should change its tint, in logical screen
+ * coordinates
+ */
void setIconsDarkArea(Rect r);
- LightBarTransitionsController getTransitionsController();
+ /**
+ * Adds a receiver to receive callbacks onDarkChanged
+ */
void addDarkReceiver(DarkReceiver receiver);
+
+ /**
+ * Adds a receiver to receive callbacks onDarkChanged
+ */
void addDarkReceiver(ImageView imageView);
- // Must have been previously been added through one of the addDarkReceive methods above.
+ /**
+ * Must have been previously been added through one of the addDarkReceive methods above.
+ */
void removeDarkReceiver(DarkReceiver object);
- void removeDarkReceiver(ImageView object);
-
- // Used to reapply darkness on an object, must have previously been added through
- // addDarkReceiver.
- void applyDark(DarkReceiver object);
/**
- * Dumpable interface
+ * Must have been previously been added through one of the addDarkReceive methods above.
*/
- default void dump(FileDescriptor fd, PrintWriter pw, String[] args) {}
+ void removeDarkReceiver(ImageView object);
+
+ /**
+ * Used to reapply darkness on an object, must have previously been added through
+ * addDarkReceiver.
+ */
+ void applyDark(DarkReceiver object);
int DEFAULT_ICON_TINT = Color.WHITE;
Rect sTmpRect = new Rect();
int[] sTmpInt2 = new int[2];
/**
- * @return the tint to apply to {@param view} depending on the desired tint {@param color} and
- * the screen {@param tintArea} in which to apply that tint
+ * @return the tint to apply to view depending on the desired tint color and
+ * the screen tintArea in which to apply that tint
*/
static int getTint(Rect tintArea, View view, int color) {
if (isInArea(tintArea, view)) {
@@ -67,8 +85,8 @@ public interface DarkIconDispatcher extends Dumpable {
}
/**
- * @return the dark intensity to apply to {@param view} depending on the desired dark
- * {@param intensity} and the screen {@param tintArea} in which to apply that intensity
+ * @return the dark intensity to apply to view depending on the desired dark
+ * intensity and the screen tintArea in which to apply that intensity
*/
static float getDarkIntensity(Rect tintArea, View view, float intensity) {
if (isInArea(tintArea, view)) {
@@ -79,7 +97,7 @@ public interface DarkIconDispatcher extends Dumpable {
}
/**
- * @return true if more than half of the {@param view} area are in {@param area}, false
+ * @return true if more than half of the view area are in area, false
* otherwise
*/
static boolean isInArea(Rect area, View view) {
@@ -99,7 +117,12 @@ public interface DarkIconDispatcher extends Dumpable {
return majorityOfWidth && coversFullStatusBar;
}
+ /**
+ * Receives a callback on darkness changes
+ */
+ @ProvidesInterface(version = DarkReceiver.VERSION)
interface DarkReceiver {
+ int VERSION = 1;
void onDarkChanged(Rect area, float darkIntensity, int tint);
}
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 73f5116bd71f..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png
deleted file mode 100755
index 9afd8fa14d31..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 552a3d1ff43a..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/search_panel_scrim.xml b/packages/SystemUI/res/drawable-land/search_panel_scrim.xml
deleted file mode 100644
index 102cc9c16a9e..000000000000
--- a/packages/SystemUI/res/drawable-land/search_panel_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:type="linear"
- android:angle="180"
- android:startColor="#55000000"
- android:endColor="#00000000" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 787e2593789b..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png
deleted file mode 100755
index 35737aa704ea..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 48b96d810a0a..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml b/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml
deleted file mode 100644
index f663a661f3f1..000000000000
--- a/packages/SystemUI/res/drawable-nodpi/scorecard_gameover.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle"
- >
- <corners
- android:radius="8dp" />
- <solid
- android:color="#ffff0000" />
-</shape>
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 23ec6dbde642..000000000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index e4500587e5b5..000000000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index d18e41906f57..000000000000
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index 00a751cfe3a4..000000000000
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml b/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml
deleted file mode 100644
index bbb2617db4a0..000000000000
--- a/packages/SystemUI/res/drawable-sw600dp/search_panel_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:type="linear"
- android:angle="90"
- android:startColor="#55000000"
- android:endColor="#00000000" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png
deleted file mode 100644
index b336ccd2b5a1..000000000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_light_old.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
deleted file mode 100644
index 6ebbc831605f..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_cancel_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png b/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png
deleted file mode 100755
index f1bfa891d229..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_dismiss_outline.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index e49db340dcfe..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
deleted file mode 100644
index b91704a928ab..000000000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_lights_out_dot_large.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/dismiss_all_shape.xml b/packages/SystemUI/res/drawable/dismiss_all_shape.xml
deleted file mode 100644
index fb371c6beb07..000000000000
--- a/packages/SystemUI/res/drawable/dismiss_all_shape.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="17dp"
- android:width="85dp"
- android:viewportHeight="48"
- android:viewportWidth="260" >
- <group
- android:name="dismiss_all"
- android:translateX="48"
- android:translateY="6" >
- <group
- android:name="3"
- android:translateX="-24"
- android:translateY="36" >
- <path
- android:name="rectangle_path_1_2"
- android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- <group
- android:name="2"
- android:translateX="-12"
- android:translateY="18" >
- <path
- android:name="rectangle_path_1_1"
- android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- <group
- android:name="1" >
- <path
- android:name="rectangle_path_1"
- android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml b/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml
new file mode 100644
index 000000000000..75311f44dfe3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml
@@ -0,0 +1,517 @@
+<?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
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_N_1_T_0"
+ android:translateX="30"
+ android:translateY="30">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-30"
+ android:translateY="-30">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorError"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorError"
+ android:trimPathStart="0.34"
+ android:trimPathEnd="0.5700000000000001"
+ android:trimPathOffset="0" />
+ <group
+ android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0"
+ android:scaleX="0.3"
+ android:scaleY="0.3"
+ android:translateX="37.788"
+ android:translateY="19.53">
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="0"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+ android:scaleX="0.3"
+ android:scaleY="0.3"
+ android:translateX="22.005"
+ android:translateY="19.51">
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="0"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+ android:translateX="30.3"
+ android:translateY="29.215">
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorError"
+ android:fillType="nonZero"
+ android:pathData=" M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="83"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="83"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="strokeWidth"
+ android:startOffset="0"
+ android:valueFrom="2.5"
+ android:valueTo="2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+ android:valueTo="M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="trimPathStart"
+ android:startOffset="0"
+ android:valueFrom="0.34"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0.5700000000000001"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="83"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:pathData="M 37.788,19.53C 38.3400184636116,20.241653709411622 37.235981536388394,18.81834629058838 37.788,19.53"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:pathData="M 37.788,19.53C 38.3400184636116,20.241653709411622 40.5479815363884,23.08834629058838 41.1,23.8"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="50">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.3"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.3"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="117"
+ android:propertyName="scaleX"
+ android:startOffset="50"
+ android:valueFrom="0.3"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="117"
+ android:propertyName="scaleY"
+ android:startOffset="50"
+ android:valueFrom="0.3"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="83"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:pathData="M 22.005,19.51C 21.43742198228836,20.224974105358122 22.57257801771164,18.79502589464188 22.005,19.51"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:pathData="M 22.005,19.51C 21.43742198228836,20.224974105358122 19.16757801771164,23.08502589464188 18.6,23.8"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="50">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.3"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.3"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="117"
+ android:propertyName="scaleX"
+ android:startOffset="50"
+ android:valueFrom="0.3"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="117"
+ android:propertyName="scaleY"
+ android:startOffset="50"
+ android:valueFrom="0.3"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillColor"
+ android:startOffset="83"
+ android:valueFrom="?android:attr/colorError"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="150"
+ android:pathData="M 30.3,29.215C 30.3,29.58759101867676 30.3,31.077408981323238 30.3,31.45"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c "
+ android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.321,0 0.67,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="pathData"
+ android:startOffset="83"
+ android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+ android:valueTo="M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.568,0 0.456,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml b/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml
new file mode 100644
index 000000000000..e4ace67577c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml
@@ -0,0 +1,637 @@
+<?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
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_N_2_T_0"
+ android:translateX="30"
+ android:translateY="30">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-30"
+ android:translateY="-30">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="0.08"
+ android:scaleY="0.08"
+ android:translateX="30.1"
+ android:translateY="30.083">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="?android:attr/colorAccent"
+ android:fillType="nonZero"
+ android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+ android:trimPathStart="0"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:scaleX="0.08"
+ android:scaleY="0.08"
+ android:translateX="30.1"
+ android:translateY="30.083">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+ android:strokeWidth="20"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:trimPathStart="0"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0" />
+ </group>
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ <group
+ android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+ android:pivotX="1.05"
+ android:pivotY="-9.891"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="29.044"
+ android:translateY="41.647">
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:pathData=" M4.71 1.1 C3.71,2.12 2.32,2.75 0.79,2.75 C-2.25,2.75 -4.7,0.29 -4.7,-2.75 "
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="41.1"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorAccent"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="18.6"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_5_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorAccent"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="30.727"
+ android:translateY="31.703">
+ <path
+ android:name="_R_G_L_0_G_D_6_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorAccent"
+ android:fillType="nonZero"
+ android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="trimPathEnd"
+ android:startOffset="33"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="trimPathEnd"
+ android:startOffset="33"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="?android:attr/colorAccent"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="67"
+ android:valueFrom="?android:attr/colorAccent"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="strokeAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.65"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.65"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="trimPathStart"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_5_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_6_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml
new file mode 100644
index 000000000000..b09f69b742bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml
@@ -0,0 +1,637 @@
+<?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
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_N_2_T_0"
+ android:translateX="30"
+ android:translateY="30">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-30"
+ android:translateY="-30">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="0.08"
+ android:scaleY="0.08"
+ android:translateX="30.1"
+ android:translateY="30.083">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="0"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+ android:trimPathStart="0"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:scaleX="0.08"
+ android:scaleY="0.08"
+ android:translateX="30.1"
+ android:translateY="30.083">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+ android:strokeWidth="20"
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:trimPathStart="0"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0" />
+ </group>
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ <group
+ android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+ android:pivotX="1.05"
+ android:pivotY="-9.891"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="29.044"
+ android:translateY="41.647">
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:pathData=" M4.71 1.1 C3.71,2.12 2.32,2.75 0.79,2.75 C-2.25,2.75 -4.7,0.29 -4.7,-2.75 "
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="41.1"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="18.6"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_5_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="30.727"
+ android:translateY="31.703">
+ <path
+ android:name="_R_G_L_0_G_D_6_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="trimPathEnd"
+ android:startOffset="33"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="0.08"
+ android:valueTo="0.08"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleX"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="scaleY"
+ android:startOffset="33"
+ android:valueFrom="0.08"
+ android:valueTo="0.12789"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="200"
+ android:valueFrom="0.12789"
+ android:valueTo="0.12241"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="300"
+ android:valueFrom="0.12241"
+ android:valueTo="0.125"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="233"
+ android:propertyName="trimPathEnd"
+ android:startOffset="33"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="67"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="strokeAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.65"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.65"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="trimPathStart"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_5_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_6_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="383"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml
new file mode 100644
index 000000000000..9259dc7bb977
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml
@@ -0,0 +1,178 @@
+<?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
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportHeight="60"
+ android:viewportWidth="60">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_N_1_T_0"
+ android:translateX="30"
+ android:translateY="30">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-30"
+ android:translateY="-30">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M39 23.8 C39,25 39.9,25.9 41.1,25.9 C42.2,25.9 43.2,25 43.2,23.8 C43.2,22.6 42.3,21.7 41.1,21.7 C39.9,21.7 39,22.6 39,23.8c " />
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M16.5 23.8 C16.5,25 17.4,25.9 18.6,25.9 C19.8,25.9 20.7,25 20.7,23.8 C20.7,22.6 19.8,21.7 18.6,21.7 C17.4,21.7 16.5,22.6 16.5,23.8c " />
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M32.9 34.7 C32.9,34.7 27.7,34.7 27.7,34.7 C27.7,34.7 27.7,32.7 27.7,32.7 C27.7,32.7 30.9,32.7 30.9,32.7 C30.9,32.7 30.9,28.2 30.9,28.2 C30.9,28.2 32.9,28.2 32.9,28.2 C32.9,28.2 32.9,34.7 32.9,34.7c " />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorAccent"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml b/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml
new file mode 100644
index 000000000000..a96d21addb2b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml
@@ -0,0 +1,473 @@
+<?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
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_N_1_T_0"
+ android:translateX="30"
+ android:translateY="30">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-30"
+ android:translateY="-30">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeWidth="2.5"
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+ android:strokeWidth="2"
+ android:strokeAlpha="1"
+ android:strokeColor="@color/biometric_face_icon_gray"
+ android:trimPathStart="0"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0" />
+ <group
+ android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="41.1"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="18.6"
+ android:translateY="23.8">
+ <path
+ android:name="_R_G_L_0_G_D_3_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+ android:translateX="30.3"
+ android:translateY="31.45">
+ <path
+ android:name="_R_G_L_0_G_D_4_P_0"
+ android:fillAlpha="1"
+ android:fillColor="@color/biometric_face_icon_gray"
+ android:fillType="nonZero"
+ android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+ </group>
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="50"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="strokeColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="strokeColor"
+ android:startOffset="50"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="strokeWidth"
+ android:startOffset="0"
+ android:valueFrom="2"
+ android:valueTo="2.5"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+ android:valueTo="M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="trimPathStart"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0.34"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="trimPathEnd"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.5700000000000001"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="50"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:pathData="M 41.1,23.8C 40.547981774806985,23.08834635019302 38.34001822519301,20.24165364980698 37.788,19.53"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillAlpha"
+ android:startOffset="50"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:pathData="M 18.6,23.8C 19.16757813692093,23.08502601385117 21.43742186307907,20.224973986148832 22.005,19.51"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="0.3"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="fillColor"
+ android:startOffset="0"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="@color/biometric_face_icon_gray"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="17"
+ android:propertyName="fillColor"
+ android:startOffset="50"
+ android:valueFrom="@color/biometric_face_icon_gray"
+ android:valueTo="?android:attr/colorError"
+ android:valueType="colorType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:pathData="M 30.3,31.45C 30.3,31.07740886211395 30.3,31.82259113788605 30.3,31.45"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="0">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:pathData="M 30.3,31.45C 30.3,31.07740886211395 30.3,29.58759113788605 30.3,29.215"
+ android:propertyName="translateXY"
+ android:propertyXName="translateX"
+ android:propertyYName="translateY"
+ android:startOffset="67">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_4_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="67"
+ android:propertyName="pathData"
+ android:startOffset="0"
+ android:valueFrom="M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c "
+ android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="pathData"
+ android:startOffset="67"
+ android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+ android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-13.15 -1.5,-13.15 C-1.5,-13.15 0.9,-13.15 0.9,-13.15 C0.9,-13.15 0.9,3.25 0.9,3.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="pathData"
+ android:startOffset="217"
+ android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-13.15 -1.5,-13.15 C-1.5,-13.15 0.9,-13.15 0.9,-13.15 C0.9,-13.15 0.9,3.25 0.9,3.25c "
+ android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="translateX"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_icon.xml b/packages/SystemUI/res/drawable/face_dialog_icon.xml
deleted file mode 100644
index 6d28b5a105f2..000000000000
--- a/packages/SystemUI/res/drawable/face_dialog_icon.xml
+++ /dev/null
@@ -1,24 +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
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:width="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path android:fillColor="#000" android:pathData="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
index af25e44bd746..8f411f4c07fe 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -18,133 +18,138 @@
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
- android:width="24dp"
- android:height="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24">
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportHeight="60"
+ android:viewportWidth="60">
<group android:name="_R_G">
<group
- android:name="_R_G_L_2_G"
- android:pivotX="-33"
- android:pivotY="-34"
- android:rotation="180"
- android:scaleX="0.738"
- android:scaleY="0.738"
- android:translateX="45"
- android:translateY="46.4">
- <path
- android:name="_R_G_L_2_G_D_0_P_0"
- android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_2_G_D_1_P_0"
- android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_2_G_D_2_P_0"
- android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="1" />
- <path
- android:name="_R_G_L_2_G_D_3_P_0"
- android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="1" />
- <path
- android:name="_R_G_L_2_G_D_4_P_0"
- android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- </group>
- <group
- android:name="_R_G_L_1_G"
- android:rotation="10"
- android:translateX="12"
- android:translateY="12">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="2"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- </group>
- <group
- android:name="_R_G_L_0_G"
- android:translateX="12"
- android:translateY="12">
+ android:name="_R_G_L_1_G_N_4_T_0"
+ android:translateX="30"
+ android:translateY="30">
<group
- android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
- android:pivotY="-0.012"
- android:rotation="0"
- android:scaleX="1"
- android:scaleY="1">
+ android:name="_R_G_L_1_G"
+ android:pivotX="114"
+ android:pivotY="114"
+ android:scaleX="0.42200000000000004"
+ android:scaleY="0.42200000000000004"
+ android:translateX="-114"
+ android:translateY="-114">
+ <path
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
<path
- android:name="_R_G_L_0_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="?android:attr/colorError"
- android:fillType="nonZero"
- android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_2_P_0"
+ android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_3_P_0"
+ android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_4_P_0"
+ android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="0"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_4_T_0"
+ android:translateX="30"
+ android:translateY="30">
<group
- android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
- android:pivotY="-0.012"
- android:rotation="0"
- android:scaleX="1"
- android:scaleY="1">
+ android:name="_R_G_L_0_G"
+ android:translateX="-30.05"
+ android:translateY="-30">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="30"
+ android:translateY="38.75">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorError"
+ android:fillType="nonZero"
+ android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:pivotX="0.002"
+ android:pivotY="7.488"
+ android:scaleX="1"
+ android:scaleY="1"
+ android:translateX="30"
+ android:translateY="25">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorError"
+ android:fillType="nonZero"
+ android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
+ </group>
<path
- android:name="_R_G_L_0_G_D_0_P_1"
- android:fillAlpha="1"
- android:fillColor="?android:attr/colorError"
- android:fillType="nonZero"
- android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorError"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
</group>
</group>
<group android:name="time_group" />
</vector>
</aapt:attr>
- <target android:name="_R_G_L_2_G_D_0_P_0">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="350"
+ android:duration="83"
android:propertyName="trimPathEnd"
android:startOffset="0"
android:valueFrom="0"
@@ -155,9 +160,9 @@
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="350"
+ android:duration="250"
android:propertyName="trimPathEnd"
- android:startOffset="350"
+ android:startOffset="83"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
@@ -168,11 +173,11 @@
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_1_P_0">
+ <target android:name="_R_G_L_1_G_D_1_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="267"
+ android:duration="83"
android:propertyName="trimPathEnd"
android:startOffset="0"
android:valueFrom="0"
@@ -183,9 +188,9 @@
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="433"
+ android:duration="250"
android:propertyName="trimPathEnd"
- android:startOffset="267"
+ android:startOffset="83"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
@@ -196,67 +201,39 @@
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_2_P_0">
+ <target android:name="_R_G_L_1_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="250"
- android:propertyName="trimPathStart"
+ android:duration="83"
+ android:propertyName="trimPathEnd"
android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathStart"
- android:startOffset="250"
- android:valueFrom="1"
+ android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_3_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="350"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="1"
+ android:duration="250"
+ android:propertyName="trimPathEnd"
+ android:startOffset="83"
+ android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="117"
- android:propertyName="trimPathStart"
- android:startOffset="350"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_4_P_0">
+ <target android:name="_R_G_L_1_G_D_3_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="417"
+ android:duration="83"
android:propertyName="trimPathEnd"
android:startOffset="0"
android:valueFrom="0"
@@ -267,9 +244,9 @@
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="117"
+ android:duration="250"
android:propertyName="trimPathEnd"
- android:startOffset="417"
+ android:startOffset="83"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
@@ -280,43 +257,26 @@
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G">
+ <target android:name="_R_G_L_1_G_D_4_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="200"
- android:propertyName="rotation"
+ android:duration="83"
+ android:propertyName="trimPathEnd"
android:startOffset="0"
- android:valueFrom="180"
- android:valueTo="180"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="500"
- android:propertyName="rotation"
- android:startOffset="200"
- android:valueFrom="180"
+ android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_0_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="383"
+ android:duration="250"
android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="0"
+ android:startOffset="83"
+ android:valueFrom="0"
+ android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
@@ -325,185 +285,129 @@
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_1_G">
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="33"
- android:propertyName="rotation"
+ android:duration="67"
+ android:propertyName="scaleX"
android:startOffset="0"
- android:valueFrom="10"
- android:valueTo="10"
+ android:valueFrom="1"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="367"
- android:propertyName="rotation"
- android:startOffset="33"
- android:valueFrom="10"
- android:valueTo="-180"
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="17"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="0"
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="67"
+ android:valueFrom="1.1"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="417"
- android:propertyName="rotation"
- android:startOffset="17"
- android:valueFrom="0"
- android:valueTo="-180"
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="67"
+ android:valueFrom="1.1"
+ android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="117"
+ android:duration="67"
android:propertyName="scaleX"
android:startOffset="0"
android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="117"
+ android:duration="67"
android:propertyName="scaleY"
android:startOffset="0"
android:valueFrom="1"
- android:valueTo="1"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="317"
+ android:duration="100"
android:propertyName="scaleX"
- android:startOffset="117"
+ android:startOffset="67"
android:valueFrom="1"
- android:valueTo="0"
+ android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="317"
+ android:duration="100"
android:propertyName="scaleY"
- android:startOffset="117"
- android:valueFrom="1"
+ android:startOffset="67"
+ android:valueFrom="1.1"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
+ <target android:name="_R_G_L_0_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="17"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="417"
- android:propertyName="rotation"
- android:startOffset="17"
- android:valueFrom="0"
- android:valueTo="-180"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="117"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="117"
- android:propertyName="scaleY"
+ android:duration="67"
+ android:propertyName="trimPathEnd"
android:startOffset="0"
android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="317"
- android:propertyName="scaleX"
- android:startOffset="117"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="317"
- android:propertyName="scaleY"
- android:startOffset="117"
+ android:duration="133"
+ android:propertyName="trimPathEnd"
+ android:startOffset="67"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -513,7 +417,7 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="717"
+ android:duration="350"
android:propertyName="translateX"
android:startOffset="0"
android:valueFrom="0"
@@ -522,4 +426,4 @@
</set>
</aapt:attr>
</target>
-</animated-vector>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
index 1a7a846b140e..89b822840b14 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -18,821 +18,374 @@
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
- android:width="24dp"
- android:height="24dp"
- android:viewportHeight="24"
- android:viewportWidth="24">
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportHeight="60"
+ android:viewportWidth="60">
<group android:name="_R_G">
<group
- android:name="_R_G_L_3_G"
- android:pivotX="-33"
- android:pivotY="-34"
- android:rotation="0"
- android:scaleX="0.738"
- android:scaleY="0.738"
- android:translateX="45"
- android:translateY="46.4">
- <path
- android:name="_R_G_L_3_G_D_0_P_0"
- android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_3_G_D_1_P_0"
- android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_3_G_D_2_P_0"
- android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_3_G_D_3_P_0"
- android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_3_G_D_4_P_0"
- android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorAccent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- </group>
- <group
- android:name="_R_G_L_2_G"
- android:pivotX="-33"
- android:pivotY="-34"
- android:rotation="0"
- android:scaleX="0.738"
- android:scaleY="0.738"
- android:translateX="45"
- android:translateY="46.4">
- <path
- android:name="_R_G_L_2_G_D_0_P_0"
- android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_2_G_D_1_P_0"
- android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_2_G_D_2_P_0"
- android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_2_G_D_3_P_0"
- android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="1" />
- <path
- android:name="_R_G_L_2_G_D_4_P_0"
- android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="1.45"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- </group>
- <group
- android:name="_R_G_L_1_G"
- android:rotation="190"
- android:translateX="12"
- android:translateY="12">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
- android:strokeAlpha="1"
- android:strokeColor="?android:attr/colorError"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="2"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="1" />
- </group>
- <group
- android:name="_R_G_L_0_G"
- android:translateX="12"
- android:translateY="12">
+ android:name="_R_G_L_1_G_N_4_T_0"
+ android:translateX="30"
+ android:translateY="30">
<group
- android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
- android:pivotY="-0.012"
- android:rotation="184"
- android:scaleX="0"
- android:scaleY="0">
+ android:name="_R_G_L_1_G"
+ android:pivotX="114"
+ android:pivotY="114"
+ android:scaleX="0.42244"
+ android:scaleY="0.42244"
+ android:translateX="-114"
+ android:translateY="-114">
<path
- android:name="_R_G_L_0_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="?android:attr/colorError"
- android:fillType="nonZero"
- android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
+ android:name="_R_G_L_1_G_D_0_P_0"
+ android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_1_P_0"
+ android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_2_P_0"
+ android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_3_P_0"
+ android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="_R_G_L_1_G_D_4_P_0"
+ android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorAccent"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="5.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
+ </group>
+ <group
+ android:name="_R_G_L_0_G_N_4_T_0"
+ android:translateX="30"
+ android:translateY="30">
<group
- android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
- android:pivotY="-0.012"
- android:rotation="184"
- android:scaleX="0"
- android:scaleY="0">
+ android:name="_R_G_L_0_G"
+ android:translateX="-30.05"
+ android:translateY="-30">
+ <group
+ android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+ android:scaleX="0"
+ android:scaleY="0"
+ android:translateX="30"
+ android:translateY="38.75">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorError"
+ android:fillType="nonZero"
+ android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
+ </group>
+ <group
+ android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+ android:pivotX="0.002"
+ android:pivotY="7.488"
+ android:scaleX="1"
+ android:scaleY="0"
+ android:translateX="30"
+ android:translateY="25">
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:fillAlpha="1"
+ android:fillColor="?android:attr/colorError"
+ android:fillType="nonZero"
+ android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
+ </group>
<path
- android:name="_R_G_L_0_G_D_0_P_1"
- android:fillAlpha="1"
- android:fillColor="?android:attr/colorError"
- android:fillType="nonZero"
- android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+ android:strokeAlpha="1"
+ android:strokeColor="?android:attr/colorError"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round"
+ android:strokeWidth="2.5"
+ android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:trimPathStart="1" />
</group>
</group>
</group>
<group android:name="time_group" />
</vector>
</aapt:attr>
- <target android:name="_R_G_L_3_G_D_0_P_0">
+ <target android:name="_R_G_L_1_G_D_0_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="150"
+ android:duration="167"
android:propertyName="trimPathStart"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_3_G_D_1_P_0">
+ <target android:name="_R_G_L_1_G_D_1_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="33"
+ android:duration="167"
android:propertyName="trimPathStart"
android:startOffset="0"
android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="150"
- android:propertyName="trimPathStart"
- android:startOffset="33"
- android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_3_G_D_2_P_0">
+ <target android:name="_R_G_L_1_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="17"
+ android:duration="167"
android:propertyName="trimPathStart"
android:startOffset="0"
android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="217"
- android:propertyName="trimPathStart"
- android:startOffset="17"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_3_G_D_3_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="17"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="133"
- android:propertyName="trimPathEnd"
- android:startOffset="17"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_3_G_D_4_P_0">
+ <target android:name="_R_G_L_1_G_D_3_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="17"
+ android:duration="167"
android:propertyName="trimPathStart"
android:startOffset="0"
android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="trimPathStart"
- android:startOffset="17"
- android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_3_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="100"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="567"
- android:propertyName="rotation"
- android:startOffset="100"
- android:valueFrom="0"
- android:valueTo="-305"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_0_P_0">
+ <target android:name="_R_G_L_1_G_D_4_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="150"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
android:duration="167"
android:propertyName="trimPathStart"
- android:startOffset="150"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_0_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathEnd"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_1_P_0">
+ <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="133"
- android:propertyName="trimPathStart"
+ android:duration="167"
+ android:propertyName="scaleX"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="200"
- android:propertyName="trimPathStart"
- android:startOffset="133"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_1_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="17"
- android:propertyName="trimPathEnd"
+ android:duration="167"
+ android:propertyName="scaleY"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="217"
- android:propertyName="trimPathEnd"
- android:startOffset="17"
+ android:duration="100"
+ android:propertyName="scaleX"
+ android:startOffset="167"
android:valueFrom="0"
- android:valueTo="1"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_2_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="133"
- android:propertyName="trimPathStart"
- android:startOffset="0"
+ android:duration="100"
+ android:propertyName="scaleY"
+ android:startOffset="167"
android:valueFrom="0"
- android:valueTo="0"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="200"
- android:propertyName="trimPathStart"
- android:startOffset="133"
- android:valueFrom="0"
+ android:duration="67"
+ android:propertyName="scaleX"
+ android:startOffset="267"
+ android:valueFrom="1.1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_2_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
+ android:duration="67"
+ android:propertyName="scaleY"
+ android:startOffset="267"
+ android:valueFrom="1.1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_2_G_D_3_P_0">
+ <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_3_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="117"
- android:propertyName="trimPathEnd"
+ android:propertyName="scaleX"
android:startOffset="0"
android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="117"
- android:propertyName="trimPathEnd"
- android:startOffset="117"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_4_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="100"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="trimPathStart"
- android:startOffset="100"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G_D_4_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="133"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_2_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="100"
- android:propertyName="rotation"
+ android:duration="167"
+ android:propertyName="scaleY"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="567"
- android:propertyName="rotation"
- android:startOffset="100"
- android:valueFrom="0"
- android:valueTo="-305"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_0_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="533"
- android:propertyName="trimPathStart"
+ android:duration="100"
+ android:propertyName="scaleX"
android:startOffset="167"
android:valueFrom="1"
- android:valueTo="0"
+ android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
<objectAnimator
- android:duration="150"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="190"
- android:valueTo="190"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="550"
- android:propertyName="rotation"
- android:startOffset="150"
- android:valueFrom="190"
- android:valueTo="-6"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="283"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="184"
- android:valueTo="184"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="317"
- android:propertyName="rotation"
- android:startOffset="283"
- android:valueFrom="184"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="283"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="283"
+ android:duration="100"
android:propertyName="scaleY"
- android:startOffset="0"
+ android:startOffset="167"
android:valueFrom="0"
- android:valueTo="0"
+ android:valueTo="1.1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="317"
+ android:duration="67"
android:propertyName="scaleX"
- android:startOffset="283"
- android:valueFrom="0"
+ android:startOffset="267"
+ android:valueFrom="1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
- android:duration="317"
+ android:duration="67"
android:propertyName="scaleY"
- android:startOffset="283"
- android:valueFrom="0"
+ android:startOffset="267"
+ android:valueFrom="1.1"
android:valueTo="1"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="283"
- android:propertyName="rotation"
- android:startOffset="0"
- android:valueFrom="184"
- android:valueTo="184"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="317"
- android:propertyName="rotation"
- android:startOffset="283"
- android:valueFrom="184"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
+ <target android:name="_R_G_L_0_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="283"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="283"
- android:propertyName="scaleY"
+ android:duration="267"
+ android:propertyName="trimPathStart"
android:startOffset="0"
- android:valueFrom="0"
+ android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="317"
- android:propertyName="scaleX"
- android:startOffset="283"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="317"
- android:propertyName="scaleY"
- android:startOffset="283"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
@@ -842,7 +395,7 @@
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
- android:duration="717"
+ android:duration="350"
android:propertyName="translateX"
android:startOffset="0"
android:valueFrom="0"
@@ -851,4 +404,4 @@
</set>
</aapt:attr>
</target>
-</animated-vector>
+</animated-vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_icon.xml b/packages/SystemUI/res/drawable/fingerprint_icon.xml
deleted file mode 100644
index 76a86ae42da2..000000000000
--- a/packages/SystemUI/res/drawable/fingerprint_icon.xml
+++ /dev/null
@@ -1,107 +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
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#1A73E8"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 30 0 C 46.5685424949 0 60 13.4314575051 60 30 C 60 46.5685424949 46.5685424949 60 30 60 C 13.4314575051 60 0 46.5685424949 0 30 C 0 13.4314575051 13.4314575051 0 30 0 Z" />
- <group
- android:translateX="17.727273"
- android:translateY="16.363636">
- <path
- android:fillColor="#FFFFFF"
- android:strokeWidth="1"
- android:pathData="M20.3065726,3.44516129 C20.1974817,3.44516129 20.0883908,3.41788856
-19.9929362,3.36334311 C17.3747544,2.01334311 15.111118,1.44061584
-12.3974817,1.44061584 C9.69748166,1.44061584 7.1338453,2.08152493
-4.80202711,3.36334311 C4.47475439,3.54061584 4.06566348,3.41788856
-3.87475439,3.09061584 C3.69748166,2.76334311 3.82020893,2.34061584
-4.14748166,2.16334311 C6.6838453,0.786070381 9.46566348,0.0769794721
-12.3974817,0.0769794721 C15.3020271,0.0769794721 17.8383908,0.717888563
-20.6202089,2.14970674 C20.961118,2.32697947 21.0838453,2.73607038
-20.9065726,3.06334311 C20.7838453,3.30879765 20.5520271,3.44516129
-20.3065726,3.44516129 L20.3065726,3.44516129 Z M0.792936205,10.6042522
-C0.656572568,10.6042522 0.520208932,10.5633431 0.397481659,10.4815249
-C0.0838452956,10.2633431 0.0156634774,9.84061584 0.233845296,9.52697947
-C1.5838453,7.61788856 3.30202711,6.11788856 5.34748166,5.06788856
-C9.62929984,2.85879765 15.111118,2.84516129 19.4065726,5.0542522
-C21.4520271,6.1042522 23.1702089,7.59061584 24.5202089,9.48607038
-C24.7383908,9.78607038 24.6702089,10.222434 24.3565726,10.4406158
-C24.0429362,10.6587977 23.6202089,10.5906158 23.4020271,10.2769795
-C22.1747544,8.55879765 20.6202089,7.20879765 18.7792998,6.26788856
-C14.8656635,4.26334311 9.86111802,4.26334311 5.96111802,6.28152493
-C4.10657257,7.23607038 2.55202711,8.59970674 1.32475439,10.3178886
-C1.21566348,10.5087977 1.01111802,10.6042522 0.792936205,10.6042522
-L0.792936205,10.6042522 Z M9.31566348,27.0633431 C9.13839075,27.0633431
-8.96111802,26.9951613 8.83839075,26.8587977 C7.65202711,25.672434
-7.01111802,24.9087977 6.09748166,23.2587977 C5.15657257,21.5815249
-4.66566348,19.5360704 4.66566348,17.3406158 C4.66566348,13.2906158
-8.12929984,9.99061584 12.3838453,9.99061584 C16.6383908,9.99061584
-20.1020271,13.2906158 20.1020271,17.3406158 C20.1020271,17.722434
-19.8020271,18.022434 19.4202089,18.022434 C19.0383908,18.022434
-18.7383908,17.722434 18.7383908,17.3406158 C18.7383908,14.0406158
-15.8883908,11.3542522 12.3838453,11.3542522 C8.87929984,11.3542522
-6.02929984,14.0406158 6.02929984,17.3406158 C6.02929984,19.3042522
-6.46566348,21.1178886 7.29748166,22.5906158 C8.17020893,24.1587977
-8.77020893,24.8269795 9.82020893,25.8906158 C10.0792998,26.1633431
-10.0792998,26.5860704 9.82020893,26.8587977 C9.67020893,26.9951613
-9.4929362,27.0633431 9.31566348,27.0633431 Z M19.0929362,24.5406158
-C17.4702089,24.5406158 16.0383908,24.1315249 14.8656635,23.3269795
-C12.8338453,21.9497067 11.6202089,19.7133431 11.6202089,17.3406158
-C11.6202089,16.9587977 11.9202089,16.6587977 12.3020271,16.6587977
-C12.6838453,16.6587977 12.9838453,16.9587977 12.9838453,17.3406158
-C12.9838453,19.2633431 13.9656635,21.0769795 15.6292998,22.1951613
-C16.5974817,22.8497067 17.7292998,23.1633431 19.0929362,23.1633431
-C19.4202089,23.1633431 19.9656635,23.122434 20.511118,23.0269795
-C20.8792998,22.9587977 21.2338453,23.2042522 21.3020271,23.5860704
-C21.3702089,23.9542522 21.1247544,24.3087977 20.7429362,24.3769795
-C19.9656635,24.5269795 19.2838453,24.5406158 19.0929362,24.5406158
-L19.0929362,24.5406158 Z M16.3520271,27.3497067 C16.2974817,27.3497067
-16.2292998,27.3360704 16.1747544,27.322434 C14.0065726,26.722434
-12.5883908,25.9178886 11.1020271,24.4587977 C9.1929362,22.5633431
-8.1429362,20.0406158 8.1429362,17.3406158 C8.1429362,15.1315249
-10.0247544,13.3315249 12.3429362,13.3315249 C14.661118,13.3315249
-16.5429362,15.1315249 16.5429362,17.3406158 C16.5429362,18.7997067
-17.811118,19.9860704 19.3792998,19.9860704 C20.9474817,19.9860704
-22.2156635,18.7997067 22.2156635,17.3406158 C22.2156635,12.1997067
-17.7838453,8.02697947 12.3292998,8.02697947 C8.45657257,8.02697947
-4.91111802,10.1815249 3.31566348,13.522434 C2.7838453,14.6269795
-2.51111802,15.922434 2.51111802,17.3406158 C2.51111802,18.4042522
-2.60657257,20.0815249 3.42475439,22.2633431 C3.56111802,22.6178886
-3.3838453,23.0133431 3.02929984,23.1360704 C2.67475439,23.272434
-2.27929984,23.0815249 2.15657257,22.7406158 C1.48839075,20.9542522
-1.16111802,19.1815249 1.16111802,17.3406158 C1.16111802,15.7042522
-1.47475439,14.2178886 2.08839075,12.922434 C3.90202711,9.11788856
-7.92475439,6.64970674 12.3292998,6.64970674 C18.5338453,6.64970674
-23.5792998,11.4360704 23.5792998,17.3269795 C23.5792998,19.5360704
-21.6974817,21.3360704 19.3792998,21.3360704 C17.061118,21.3360704
-15.1792998,19.5360704 15.1792998,17.3269795 C15.1792998,15.8678886
-13.911118,14.6815249 12.3429362,14.6815249 C10.7747544,14.6815249
-9.50657257,15.8678886 9.50657257,17.3269795 C9.50657257,19.6587977
-10.4065726,21.8406158 12.0565726,23.4769795 C13.3520271,24.7587977
-14.5929362,25.4678886 16.5156635,25.9997067 C16.8838453,26.0951613
-17.0883908,26.4769795 16.9929362,26.8315249 C16.9247544,27.1451613
-16.6383908,27.3497067 16.3520271,27.3497067 L16.3520271,27.3497067 Z" />
- </group>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml b/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml
deleted file mode 100644
index 6134b8f75457..000000000000
--- a/packages/SystemUI/res/drawable/ic_aod_charging_24dp.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M11.0,22.98l0.0,-8.98 -4.0,0.0 6.0,-13.0 0.0,9.0 4.0,0.0z"
- android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cast.xml b/packages/SystemUI/res/drawable/ic_cast.xml
deleted file mode 100644
index b86dfea07682..000000000000
--- a/packages/SystemUI/res/drawable/ic_cast.xml
+++ /dev/null
@@ -1,31 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1 18v2c0 .55 .45 1 1 1h2c0-1.66-1.34-3-3-3zm0-2.94c-.01 .51 .32 .93 .82 1.02
-2.08 .36 3.74 2 4.1 4.08 .09 .48 .5 .84 .99 .84 .61 0 1.09-.54 1-1.14a6.996
-6.996 0 0 0-5.8-5.78c-.59-.09-1.09 .38 -1.11 .98 zm0-4.03c-.01 .52 .34 .96 .85
-1.01 4.26 .43 7.68 3.82 8.1 8.08 .05 .5 .48 .88 .99 .88 .59 0 1.06-.51
-1-1.1-.52-5.21-4.66-9.34-9.87-9.85-.57-.05-1.05 .4 -1.07 .98 zM21 3H3c-1.1 0-2
-.9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_chevron_left.xml b/packages/SystemUI/res/drawable/ic_chevron_left.xml
deleted file mode 100644
index 379382b06504..000000000000
--- a/packages/SystemUI/res/drawable/ic_chevron_left.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="36.0"
- android:viewportHeight="36.0">
-
- <path
- android:fillColor="#ffffffff"
- android:pathData="M23.1,11.1l-2.1000004,-2.1000004 -9.0,9.0 9.0,9.0 2.1000004,-2.1000004 -6.8999996,-6.8999996z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_off.xml b/packages/SystemUI/res/drawable/ic_data_off.xml
deleted file mode 100644
index b97ddaef6418..000000000000
--- a/packages/SystemUI/res/drawable/ic_data_off.xml
+++ /dev/null
@@ -1,27 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M21.6,21.6L10.8,10.9L2.1,2.1L0.8,3.4l3.3,3.3C3.1,8.2 2.5,10.0 2.5,12.0c0.0,5.2 4.3,9.5 9.5,9.5c2.0,0.0 3.8,-0.6 5.3,-1.6l3.0,3.0L21.6,21.6zM9.6,12.2l0.7,0.7L9.6,12.9L9.6,12.2zM13.9,18.6c-0.2,0.2 -0.5,0.2 -0.6,0.0l-2.4,-3.7l1.5,0.0l2.4,2.4L13.9,18.6z"
- android:fillColor="#ffffff"/>
- <path
- android:pathData="M12.0,2.5c-2.0,0.0 -3.8,0.6 -5.3,1.6l2.5,2.5L10.0,5.4c0.2,-0.2 0.5,-0.2 0.6,0.0L13.0,9.1l-1.4,0.0l2.0,2.0l0.6,0.0l0.0,0.6l5.6,5.6c1.0,-1.5 1.6,-3.3 1.6,-5.3C21.5,6.8 17.2,2.5 12.0,2.5z"
- android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_on.xml b/packages/SystemUI/res/drawable/ic_data_on.xml
deleted file mode 100644
index a65dc7922ceb..000000000000
--- a/packages/SystemUI/res/drawable/ic_data_on.xml
+++ /dev/null
@@ -1,26 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M12.0,12.0m-9.5,0.0a9.5,9.5 0.0,1.0 1.0,19.0 0.0a9.5,9.5 0.0,1.0 1.0,-19.0 0.0
- M10.6,5.4c-0.2,-0.2 -0.5,-0.2 -0.6,0.0L7.6,9.1l2.0,0.0l0.0,3.8L11.0,12.900001L11.0,9.1l2.0,0.0L10.6,5.4z
- M13.3,18.6c0.2,0.2 0.5,0.2 0.6,0.0l2.4,-3.7l-2.0,0.0l0.0,-3.8l-1.4,0.0l0.0,3.8l-2.0,0.0L13.3,18.6z"
- android:fillColor="#ffffff"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_unavailable.xml b/packages/SystemUI/res/drawable/ic_data_unavailable.xml
deleted file mode 100644
index ffb2af71c546..000000000000
--- a/packages/SystemUI/res/drawable/ic_data_unavailable.xml
+++ /dev/null
@@ -1,27 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M15.8,12.9l3.7,0.0c0.0,-0.3 0.0,-0.6 0.0,-0.9c0.0,-5.2 -4.3,-9.5 -9.5,-9.5S0.6,6.8 0.6,12.0s4.3,9.5 9.5,9.5c2.1,0.0 4.1,-0.7 5.7,-1.9L15.8,12.9zM5.7,9.1l2.4,-3.7c0.2,-0.2 0.5,-0.2 0.6,0.0l2.4,3.7l-2.0,0.0l0.0,3.8L7.8,12.900001L7.8,9.1L5.7,9.1zM11.4,18.6L9.0,14.9l2.0,0.0l0.0,-3.8l1.4,0.0l0.0,3.8l2.0,0.0L12.0,18.6C11.9,18.8 11.6,18.8 11.4,18.6z"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M23.4,19.4l-2.1,-2.1 2.1,-2.199999 -1.1,-1.0 -2.099998,2.1 -2.1,-2.1 -1.1,1.099999 2.1,2.099999 -2.1,2.1 1.1,1.1 2.1,-2.200001 2.099998,2.200001z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_expand_less.xml b/packages/SystemUI/res/drawable/ic_expand_less.xml
deleted file mode 100644
index e96801353ffa..000000000000
--- a/packages/SystemUI/res/drawable/ic_expand_less.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20.0dp"
- android:height="20.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M12.000000,8.000000l-6.000000,6.000000 1.400000,1.400000 4.600000,-4.599999 4.600000,4.599999 1.400000,-1.400000z"
- android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_expand_more.xml b/packages/SystemUI/res/drawable/ic_expand_more.xml
deleted file mode 100644
index 72e98ec21897..000000000000
--- a/packages/SystemUI/res/drawable/ic_expand_more.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20.0dp"
- android:height="20.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
- android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_history.xml b/packages/SystemUI/res/drawable/ic_history.xml
deleted file mode 100644
index e936864f82ab..000000000000
--- a/packages/SystemUI/res/drawable/ic_history.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89 .07 .14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7
-7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13
-21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54 .72 -1.21-3.5-2.08V8H12z" />
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_back.xml b/packages/SystemUI/res/drawable/ic_qs_back.xml
deleted file mode 100644
index f00ba03eb829..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_back.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M20.0,11.0L7.8,11.0l5.6,-5.6L12.0,4.0l-8.0,8.0l8.0,8.0l1.4,-1.4L7.8,13.0L20.0,13.0L20.0,11.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml b/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
deleted file mode 100644
index 7b29740be338..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="24.0"
- 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"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock.xml b/packages/SystemUI/res/drawable/ic_qs_lock.xml
deleted file mode 100644
index 204af7e81f4c..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_lock.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="@color/keyguard_affordance"
- android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
deleted file mode 100644
index c877f063b7a8..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="@color/keyguard_affordance"
- android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
deleted file mode 100644
index 7bdf50c74bed..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!-- Placeholder icon for network logging until the real icon is finalized-->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12.0dp"
- android:height="12.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2,24v-4h12v4H2z M2,16v-4h20v4H2z M5,7 12,0 19,7 14,7 14,15 10,15 10,7z"/>
-
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
deleted file mode 100644
index 29741577c039..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18,17v-6c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C7.64,5.36 6,7.92 6,11v6H4v2h10h0.38H20v-2H18zM16,17H8v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5V17z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
deleted file mode 100644
index 6db508cd31e8..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4C10,21.1 10.9,22 12,22z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M16,16L2.81,2.81L1.39,4.22l4.85,4.85C6.09,9.68 6,10.33 6,11v6H4v2h12.17l3.61,3.61l1.41,-1.41L16,16zM8,17c0,0 0.01,-6.11 0.01,-6.16L14.17,17H8z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,6.5c2.49,0 4,2.02 4,4.5v2.17l2,2V11c0,-3.07 -1.63,-5.64 -4.5,-6.32V4c0,-0.83 -0.67,-1.5 -1.5,-1.5S10.5,3.17 10.5,4v0.68C9.72,4.86 9.05,5.2 8.46,5.63L9.93,7.1C10.51,6.73 11.2,6.5 12,6.5z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
deleted file mode 100644
index c87b595a20f2..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
deleted file mode 100644
index 4a2bd548f61d..000000000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<animated-vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_workmode_disable" >
- <target
- android:name="mask_1"
- android:animation="@anim/ic_signal_workmode_disable_mask_1_animation" />
- <target
- android:name="whole"
- android:animation="@anim/ic_signal_workmode_disable_whole_animation" />
- <target
- android:name="rectangle_path_3_position"
- android:animation="@anim/ic_signal_workmode_disable_rectangle_path_3_position_animation" />
- <target
- android:name="rectangle_path_3"
- android:animation="@anim/ic_signal_workmode_disable_rectangle_path_3_animation" />
- <target
- android:name="rectangle_path_4_position"
- android:animation="@anim/ic_signal_workmode_disable_rectangle_path_4_position_animation" />
- <target
- android:name="rectangle_path_4"
- android:animation="@anim/ic_signal_workmode_disable_rectangle_path_4_animation" />
- <target
- android:name="left"
- android:animation="@anim/ic_signal_workmode_disable_left_animation" />
- <target
- android:name="right"
- android:animation="@anim/ic_signal_workmode_disable_right_animation" />
- <target
- android:name="stick"
- android:animation="@anim/ic_signal_workmode_disable_stick_animation" />
- <target
- android:name="ic_signal_workmode_disable"
- android:animation="@anim/ic_signal_workmode_disable_stickito_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
deleted file mode 100644
index 2d4f0b5d162f..000000000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:name="ic_signal_workmode_enable"
- android:width="42dp"
- android:viewportWidth="42"
- android:height="42dp"
- android:viewportHeight="42" >
- <group
- android:name="suitcase"
- android:translateX="21"
- android:translateY="36.9375"
- android:scaleX="0.1"
- android:scaleY="0.1" >
- <group
- android:name="suitcase_pivot"
- android:translateY="-158" >
- <clip-path
- android:name="mask_1"
- android:pathData="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 480.0,480.0 480.0,480.0 c 0.0,0.0 -20.7500915527,20.75 -20.7500915527,20.75 c 0.0,0.0 -479.999908447,-480.000015259 -479.999908447,-480.000015259 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z" />
- <group
- android:name="whole"
- android:translateX="-1.11523"
- android:translateY="32.0918"
- android:scaleX="0"
- android:scaleY="0" >
- <path
- android:name="rectangle_path_1"
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="65"
- android:pathData="M 0.0,-66.5 l 0.0,0.0 c 36.7269358617,0.0 66.5,29.7730641383 66.5,66.5 l 0.0,0.0 c 0.0,36.7269358617 -29.7730641383,66.5 -66.5,66.5 l 0.0,0.0 c -36.7269358617,0.0 -66.5,-29.7730641383 -66.5,-66.5 l 0.0,0.0 c 0.0,-36.7269358617 29.7730641383,-66.5 66.5,-66.5 Z" />
- </group>
- <group
- android:name="handle"
- android:translateY="-100" >
- <path
- android:name="rectangle_path_2"
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="35"
- android:pathData="M -34.0,-50.0 l 68.0,0.0 c 8.8365559968,0.0 16.0,7.1634440032 16.0,16.0 l 0.0,68.0 c 0.0,8.8365559968 -7.1634440032,16.0 -16.0,16.0 l -68.0,0.0 c -8.8365559968,0.0 -16.0,-7.1634440032 -16.0,-16.0 l 0.0,-68.0 c 0.0,-8.8365559968 7.1634440032,-16.0 16.0,-16.0 Z" />
- </group>
- <group
- android:name="case"
- android:translateY="32.68518" >
- <group
- android:name="case_pivot"
- android:translateY="-32.68518" >
- <group
- android:name="bottom"
- android:translateY="-97.62964" >
- <group
- android:name="bottom_pivot"
- android:translateY="40" >
- <group
- android:name="rectangle_path_3_position"
- android:translateY="25" >
- <path
- android:name="rectangle_path_3"
- android:fillColor="#FFFFFFFF"
- android:pathData="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
- </group>
- </group>
- </group>
- <group
- android:name="top"
- android:translateY="163" >
- <group
- android:name="top_pivot"
- android:translateY="-40" >
- <group
- android:name="rectangle_path_4_position"
- android:translateY="-25" >
- <path
- android:name="rectangle_path_4"
- android:fillColor="#FFFFFFFF"
- android:pathData="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
- </group>
- </group>
- </group>
- <group
- android:name="left"
- android:translateX="-175.00635"
- android:translateY="30"
- android:scaleX="1.8" >
- <group
- android:name="left_pivot"
- android:translateX="50.00635" >
- <path
- android:name="rectangle_path_5"
- android:fillColor="#FFFFFFFF"
- android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
- </group>
- </group>
- <group
- android:name="right"
- android:translateX="174.97778"
- android:translateY="30"
- android:scaleX="1.8" >
- <group
- android:name="right_pivot"
- android:translateX="-49.97778" >
- <path
- android:name="rectangle_path_6"
- android:fillColor="#FFFFFFFF"
- android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
- </group>
- </group>
- </group>
- </group>
- <group
- android:name="stick"
- android:translateX="-166.59082"
- android:translateY="-156.51367"
- android:rotation="-45" >
- <group
- android:name="stick_pivot"
- android:translateX="0.18161"
- android:translateY="243.8158" >
- <path
- android:name="stickito"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1"
- android:pathData="M -16.5,-243.999885 l 33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 l -33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
- </group>
- </group>
- </group>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
deleted file mode 100644
index c98f800d70c1..000000000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<animated-vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_workmode_enable" >
- <target
- android:name="mask_1"
- android:animation="@anim/ic_signal_workmode_enable_mask_1_animation" />
- <target
- android:name="whole"
- android:animation="@anim/ic_signal_workmode_enable_whole_animation" />
- <target
- android:name="rectangle_path_3_position"
- android:animation="@anim/ic_signal_workmode_enable_rectangle_path_3_position_animation" />
- <target
- android:name="rectangle_path_3"
- android:animation="@anim/ic_signal_workmode_enable_rectangle_path_3_animation" />
- <target
- android:name="rectangle_path_4_position"
- android:animation="@anim/ic_signal_workmode_enable_rectangle_path_4_position_animation" />
- <target
- android:name="rectangle_path_4"
- android:animation="@anim/ic_signal_workmode_enable_rectangle_path_4_animation" />
- <target
- android:name="left"
- android:animation="@anim/ic_signal_workmode_enable_left_animation" />
- <target
- android:name="right"
- android:animation="@anim/ic_signal_workmode_enable_right_animation" />
- <target
- android:name="stick"
- android:animation="@anim/ic_signal_workmode_enable_stick_animation" />
- <target
- android:name="ic_signal_workmode_enable"
- android:animation="@anim/ic_signal_workmode_enable_stickito_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_sim.xml b/packages/SystemUI/res/drawable/ic_sim.xml
deleted file mode 100644
index a9a19027a8b1..000000000000
--- a/packages/SystemUI/res/drawable/ic_sim.xml
+++ /dev/null
@@ -1,42 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M18,2h-8L4,8v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4C20,2.9 19.1,2 18,2zM18,4v16H6V8.83L10.83,4L18,4L18,4z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M7,17h2v2h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15,17h2v2h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M7,11h2v4h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M11,15h2v4h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M11,11h2v2h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15,11h2v4h-2z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_speaker.xml b/packages/SystemUI/res/drawable/ic_speaker.xml
deleted file mode 100644
index 1ea293c0b690..000000000000
--- a/packages/SystemUI/res/drawable/ic_speaker.xml
+++ /dev/null
@@ -1,26 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal" >
- <path
- android:pathData="M17,2L7,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,1.99 2,1.99L17,22c1.1,0 2,-0.9 2,-2L19,4c0,-1.1 -0.9,-2 -2,-2zM12,4c1.1,0 2,0.9 2,2s-0.9,2 -2,2c-1.11,0 -2,-0.9 -2,-2s0.89,-2 2,-2zM12,20c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"
- android:fillColor="#FFFFFFFF"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_speaker_group.xml b/packages/SystemUI/res/drawable/ic_speaker_group.xml
deleted file mode 100644
index d6867d7265b0..000000000000
--- a/packages/SystemUI/res/drawable/ic_speaker_group.xml
+++ /dev/null
@@ -1,32 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal" >
- <path
- android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"
- android:fillColor="#FFFFFFFF"/>
- <path
- android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
- android:fillColor="#FFFFFFFF"/>
- <path
- android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z"
- android:fillColor="#FFFFFFFF"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_swap.xml b/packages/SystemUI/res/drawable/ic_swap.xml
deleted file mode 100644
index 30da2a9f532f..000000000000
--- a/packages/SystemUI/res/drawable/ic_swap.xml
+++ /dev/null
@@ -1,25 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorForeground">
- <path
- android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
- android:fillColor="#FFFFFF"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_tv.xml b/packages/SystemUI/res/drawable/ic_tv.xml
deleted file mode 100644
index cc2ae910ae88..000000000000
--- a/packages/SystemUI/res/drawable/ic_tv.xml
+++ /dev/null
@@ -1,26 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal" >
- <path
- android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"
- android:fillColor="#FFFFFFFF"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_zen_all.xml b/packages/SystemUI/res/drawable/ic_zen_all.xml
deleted file mode 100644
index 5df2447b9bb2..000000000000
--- a/packages/SystemUI/res/drawable/ic_zen_all.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="18dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_zen_important.xml b/packages/SystemUI/res/drawable/ic_zen_important.xml
deleted file mode 100644
index c2a59b85bf4a..000000000000
--- a/packages/SystemUI/res/drawable/ic_zen_important.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="18dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_zen_none.xml b/packages/SystemUI/res/drawable/ic_zen_none.xml
deleted file mode 100644
index 99014f24e53f..000000000000
--- a/packages/SystemUI/res/drawable/ic_zen_none.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="18dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml b/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
deleted file mode 100644
index b812d43b3b87..000000000000
--- a/packages/SystemUI/res/drawable/keyguard_overflow_number_background.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="#1a000000" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_expand_more.xml b/packages/SystemUI/res/drawable/notification_expand_more.xml
deleted file mode 100644
index 430fb0dd523d..000000000000
--- a/packages/SystemUI/res/drawable/notification_expand_more.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License._more
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="22.0dp"
- android:height="22.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
- android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pip_dismiss.xml b/packages/SystemUI/res/drawable/pip_dismiss.xml
deleted file mode 100644
index f656eeb2e5ee..000000000000
--- a/packages/SystemUI/res/drawable/pip_dismiss.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="42.0dp"
- android:height="42.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_notification_icon.xml b/packages/SystemUI/res/drawable/pip_notification_icon.xml
deleted file mode 100644
index 592bc60d553e..000000000000
--- a/packages/SystemUI/res/drawable/pip_notification_icon.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pop_ball.xml b/packages/SystemUI/res/drawable/pop_ball.xml
deleted file mode 100644
index ee1220f42140..000000000000
--- a/packages/SystemUI/res/drawable/pop_ball.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M0,50 a50,50 0 1 1 100,0
- a50,50 0 1 1 -100,0"
- android:fillColor="#FFFF1744"/>
- <path
- android:pathData="M16,36 A24,24 0 1 1 64,36
- M64,36 A24,24 0 1 1 16,36"
- android:fillColor="#20FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_belt.xml b/packages/SystemUI/res/drawable/pop_belt.xml
deleted file mode 100644
index e0ea57527d2a..000000000000
--- a/packages/SystemUI/res/drawable/pop_belt.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000m-47.599998,0.000000a47.599998,47.599998 0.000000,1.000000 1.000000,95.199997 0.000000a47.599998,47.599998 0.000000,1.000000 1.000000,-95.199997 0.000000"
- android:fillColor="#9C27B0"/>
- <path
- android:pathData="M50.000000,2.429000c-26.337999,0.000000 -47.688999,21.351000 -47.688999,47.688999c0.000000,13.168000 5.337000,25.091000 13.968000,33.722000l67.444000,-67.443001C75.092003,7.766000 63.168999,2.429000 50.000000,2.429000z"
- android:fillColor="#BA68C8"/>
- <path
- android:pathData="M0.000000,41.573002l100.000000,0.000000l0.000000,17.090000l-100.000000,0.000000z"
- android:fillColor="#9C27B0"/>
- <path
- android:pathData="M0.000000,58.662998l0.000000,-17.089996 100.000000,0.000000z"
- android:fillColor="#BA68C8"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_droid.xml b/packages/SystemUI/res/drawable/pop_droid.xml
deleted file mode 100644
index eed325c6541c..000000000000
--- a/packages/SystemUI/res/drawable/pop_droid.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
- android:fillColor="#9E9D24"/>
- <path
- android:pathData="M30.775999,24.528000m-4.209000,0.000000a4.209000,4.209000 0.000000,1.000000 1.000000,8.418000 0.000000a4.209000,4.209000 0.000000,1.000000 1.000000,-8.418000 0.000000"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M69.226997,24.528000m-4.210000,0.000000a4.210000,4.210000 0.000000,1.000000 1.000000,8.420000 0.000000a4.210000,4.210000 0.000000,1.000000 1.000000,-8.420000 0.000000"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M85.352997,14.648000C65.829002,-4.877000 34.168999,-4.877000 14.646000,14.646000C4.882000,24.410000 0.002000,37.207001 0.000000,50.000999l99.996002,0.002000C99.996002,37.207001 95.115997,24.410000 85.352997,14.648000z"
- android:fillColor="#C0CA33"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_pizza.xml b/packages/SystemUI/res/drawable/pop_pizza.xml
deleted file mode 100644
index 1806b5a17cec..000000000000
--- a/packages/SystemUI/res/drawable/pop_pizza.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M14.645000,14.645000C5.597000,23.693001 0.000000,36.193001 0.000000,50.000000l50.000000,0.000000L14.645000,14.645000z"
- android:fillColor="#2979FF"/>
- <path
- android:pathData="M100.000000,50.000000c0.000000,-13.807000 -5.597000,-26.306999 -14.645000,-35.355000L50.000000,50.000000L100.000000,50.000000z"
- android:fillColor="#FF1744"/>
- <path
- android:pathData="M85.355003,14.645000C76.306999,5.597000 63.806999,0.000000 50.000000,0.000000l0.000000,50.000000L85.355003,14.645000z"
- android:fillColor="#0F9D58"/>
- <path
- android:pathData="M50.000000,0.000000C36.193001,0.000000 23.693001,5.597000 14.645000,14.645000L50.000000,50.000000L50.000000,0.000000z"
- android:fillColor="#FFBC00"/>
- <path
- android:pathData="M50.000000,50.000000l35.355000,35.355000C94.403000,76.307999 100.000000,63.807999 100.000000,50.000000L50.000000,50.000000z"
- android:fillColor="#2979FF"/>
- <path
- android:pathData="M50.000000,100.000000c13.807000,0.000000 26.306999,-5.596000 35.355000,-14.645000L50.000000,50.000000L50.000000,100.000000z"
- android:fillColor="#FFBC00"/>
- <path
- android:pathData="M14.645000,85.355003C23.693001,94.403999 36.193001,100.000000 50.000000,100.000000L50.000000,50.000000L14.645000,85.355003z"
- android:fillColor="#0F9D58"/>
- <path
- android:pathData="M0.000000,50.000000c0.000000,13.808000 5.597000,26.308001 14.645000,35.355000L50.000000,50.000000L0.000000,50.000000z"
- android:fillColor="#FF1744"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_stripes.xml b/packages/SystemUI/res/drawable/pop_stripes.xml
deleted file mode 100644
index ef6c8e88e2bf..000000000000
--- a/packages/SystemUI/res/drawable/pop_stripes.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
- android:fillColor="#F57C00"/>
- <path
- android:pathData="M50.000999,100.000000c14.136000,0.000000 26.893000,-5.876000 35.987000,-15.308000L14.013000,84.692001C23.106001,94.124001 35.862999,100.000000 50.000999,100.000000z"
- android:fillColor="#E65100"/>
- <path
- android:pathData="M50.000999,0.000000C35.862999,0.000000 23.106001,5.876000 14.013000,15.308000l71.974998,0.000000C76.893997,5.876000 64.137001,0.000000 50.000999,0.000000z"
- android:fillColor="#FFA726"/>
- <path
- android:pathData="M96.501999,31.631001c-2.423000,-6.127000 -6.020000,-11.660000 -10.514000,-16.323000L14.013000,15.308001C9.517000,19.971001 5.922000,25.503000 3.499000,31.631001L96.501999,31.631001z"
- android:fillColor="#FB8C00"/>
- <path
- android:pathData="M3.499000,68.370003c2.423000,6.128000 6.018000,11.658000 10.514000,16.322001l71.974998,0.000000c4.494000,-4.664000 8.091000,-10.194000 10.514000,-16.322001L3.499000,68.370003z"
- android:fillColor="#EF6C00"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_swirl.xml b/packages/SystemUI/res/drawable/pop_swirl.xml
deleted file mode 100644
index f87569b4a5f8..000000000000
--- a/packages/SystemUI/res/drawable/pop_swirl.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000C86.898003,27.834999 79.244003,11.688000 76.177002,7.399000c-7.240000,-4.459000 -15.703000,-7.112000 -24.770000,-7.363000C56.247002,2.253000 70.815002,12.456000 50.000000,50.000000z"
- android:fillColor="#FFFFFA"/>
- <path
- android:pathData="M50.000000,50.000000c20.815001,-37.543999 6.247000,-47.747002 1.407000,-49.964001C50.938000,0.022000 50.472000,0.000000 50.000000,0.000000c-8.627000,0.000000 -16.743999,2.186000 -23.827000,6.032000C31.392000,5.514000 49.251999,6.903000 50.000000,50.000000z"
- android:fillColor="#76FF03"/>
- <path
- android:pathData="M50.000000,50.000000c37.543999,20.816000 47.747002,6.248000 49.965000,1.408000C99.977997,50.938000 100.000000,50.473000 100.000000,50.000000c0.000000,-8.627000 -2.186000,-16.743999 -6.032000,-23.827000C94.486000,31.393000 93.098000,49.251999 50.000000,50.000000z"
- android:fillColor="#76FF03"/>
- <path
- android:pathData="M50.000000,50.000000c43.098000,-0.748000 44.486000,-18.607000 43.967999,-23.827000c-4.186000,-7.708000 -10.344000,-14.188000 -17.791000,-18.773001C79.244003,11.688000 86.898003,27.834999 50.000000,50.000000z"
- android:fillColor="#303F9F"/>
- <path
- android:pathData="M50.000000,50.000000C27.834000,13.103000 11.687000,20.757000 7.398000,23.823999C2.940000,31.063000 0.287000,39.527000 0.035000,48.592999C2.253000,43.752998 12.456000,29.184999 50.000000,50.000000z"
- android:fillColor="#FFFFFA"/>
- <path
- android:pathData="M50.000000,50.000000C49.251999,6.903000 31.392000,5.514000 26.173000,6.032000c-7.709000,4.187000 -14.188000,10.344000 -18.774000,17.792000C11.687000,20.757000 27.834000,13.103000 50.000000,50.000000z"
- android:fillColor="#303F9F"/>
- <path
- android:pathData="M50.000000,50.000000C12.456000,29.184999 2.253000,43.752998 0.035000,48.592999C0.022000,49.062000 0.000000,49.528000 0.000000,50.000000c0.000000,8.628000 2.186000,16.743999 6.032000,23.827999C5.514000,68.609001 6.902000,50.749001 50.000000,50.000000z"
- android:fillColor="#76FF03"/>
- <path
- android:pathData="M50.000000,50.000000c0.748000,43.098000 18.608000,44.486000 23.827000,43.969002c7.709000,-4.187000 14.188000,-10.344000 18.774000,-17.791000C88.313004,79.244003 72.166000,86.898003 50.000000,50.000000z"
- android:fillColor="#303F9F"/>
- <path
- android:pathData="M50.000000,50.000000c22.166000,36.897999 38.313000,29.243999 42.602001,26.177999c4.458000,-7.240000 7.111000,-15.703000 7.363000,-24.770000C97.747002,56.248001 87.543999,70.816002 50.000000,50.000000z"
- android:fillColor="#FFFFFA"/>
- <path
- android:pathData="M50.000000,50.000000c-20.815001,37.544998 -6.247000,47.748001 -1.407000,49.965000C49.062000,99.978996 49.528000,100.000000 50.000000,100.000000c8.627000,0.000000 16.743999,-2.185000 23.827000,-6.031000C68.608002,94.486000 50.748001,93.098000 50.000000,50.000000z"
- android:fillColor="#76FF03"/>
- <path
- android:pathData="M50.000000,50.000000C13.103000,72.166000 20.757000,88.313004 23.823000,92.601997c7.240000,4.459000 15.703000,7.112000 24.770000,7.363000C43.752998,97.748001 29.184999,87.544998 50.000000,50.000000z"
- android:fillColor="#FFFFFA"/>
- <path
- android:pathData="M50.000000,50.000000C6.902000,50.749001 5.514000,68.609001 6.032000,73.828003c4.186000,7.708000 10.344000,14.188000 17.791000,18.773001C20.757000,88.313004 13.103000,72.166000 50.000000,50.000000z"
- android:fillColor="#303F9F"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_vortex.xml b/packages/SystemUI/res/drawable/pop_vortex.xml
deleted file mode 100644
index 2380e68c4c16..000000000000
--- a/packages/SystemUI/res/drawable/pop_vortex.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
- android:fillColor="#F8F8FF"/>
- <path
- android:pathData="M58.658001,89.648003c-19.330000,0.000000 -35.000000,-15.670000 -35.000000,-35.000000c0.000000,-13.531000 10.969000,-24.500000 24.500000,-24.500000c9.472000,0.000000 17.150000,7.679000 17.150000,17.150000c0.000000,6.631000 -5.375000,12.006000 -12.006000,12.006000c-3.798000,0.000000 -7.004000,-2.522000 -8.045000,-5.982000c1.021000,1.136000 2.497000,1.854000 4.145000,1.854000c2.644000,0.000000 4.853000,-1.841000 5.428000,-4.310000c0.175000,-0.558000 0.271000,-1.150000 0.271000,-1.766000c0.000000,-4.642000 -3.763000,-8.404000 -8.403000,-8.404000c-6.631000,0.000000 -12.006000,5.375000 -12.006000,12.006000c0.000000,9.472000 7.679000,17.149000 17.150000,17.149000c13.531000,0.000000 24.500000,-10.969000 24.500000,-24.500000c0.000000,-19.330000 -15.670000,-35.000000 -35.000000,-35.000000c-12.963000,0.000000 -24.773001,4.935000 -33.657001,13.025000C2.824000,31.087000 0.000000,40.212002 0.000000,50.000000c0.000000,27.615000 22.386000,50.000000 50.000000,50.000000c17.825001,0.000000 33.462002,-9.335000 42.313999,-23.375999C83.431000,84.714996 71.621002,89.648003 58.658001,89.648003z"
- android:fillColor="#7BAAF7"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/pop_vortex2.xml b/packages/SystemUI/res/drawable/pop_vortex2.xml
deleted file mode 100644
index 0a96b74cf476..000000000000
--- a/packages/SystemUI/res/drawable/pop_vortex2.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="100.0dp"
- android:height="100.0dp"
- android:viewportWidth="100.0"
- android:viewportHeight="100.0">
- <path
- android:pathData="M50.000000,50.000000m-50.000000,0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,100.000000 0.000000a50.000000,50.000000 0.000000,1.000000 1.000000,-100.000000 0.000000"
- android:fillColor="#D81B60"/>
- <path
- android:pathData="M21.250000,78.369003c-13.200000,-16.000000 -10.930000,-39.671001 5.070000,-52.870998c12.799000,-10.560000 31.737000,-8.743000 42.294998,4.057000c8.448000,10.239000 6.996000,25.389000 -3.244000,33.837002c-8.191000,6.759000 -20.311001,5.596000 -27.068001,-2.596000c-5.408000,-6.554000 -4.478000,-16.249001 2.076000,-21.656000c5.242000,-4.325000 12.998000,-3.581000 17.323999,1.661000c3.460000,4.194000 2.865000,10.399000 -1.330000,13.859000c-3.354000,2.769000 -8.318000,2.293000 -11.087000,-1.062000c-2.214000,-2.685000 -1.833000,-6.655000 0.851000,-8.870000c2.147000,-1.771000 5.324000,-1.468000 7.096000,0.681000c1.393000,1.688000 1.174000,4.165000 -0.464000,5.596000c0.409000,-0.564000 0.657000,-1.253000 0.657000,-2.004000c0.000000,-1.021000 -0.455000,-1.928000 -1.165000,-2.556000c-0.067000,-0.112000 -0.134000,-0.226000 -0.220000,-0.329000c-1.135000,-1.373000 -3.168000,-1.568000 -4.542000,-0.435000c-1.719000,1.417000 -1.962000,3.958000 -0.544000,5.677000c1.771000,2.146000 4.949000,2.451000 7.096000,0.680000c2.684000,-2.215000 3.064000,-6.186000 0.851000,-8.870000c-2.769000,-3.356000 -7.732000,-3.831000 -11.087000,-1.063000c-4.195000,3.460000 -4.790000,9.665000 -1.330000,13.859000c4.326000,5.244000 12.082000,5.987000 17.323999,1.662000c6.554000,-5.407000 7.484000,-15.102000 2.076000,-21.656000c-6.758000,-8.191000 -18.875999,-9.354000 -27.069000,-2.596000c-10.239000,8.448000 -11.691000,23.598000 -3.244000,33.837002c10.560000,12.800000 29.497000,14.616000 42.296001,4.056000c16.000000,-13.199000 18.270000,-36.869999 5.070000,-52.868999C68.397003,5.620000 52.516998,-0.139000 37.205002,1.659000c-8.665000,2.287000 -16.410999,6.836000 -22.561001,12.985000C5.597000,23.693001 0.000000,36.193001 0.000000,50.000000c0.000000,13.808000 5.597000,26.308001 14.645000,35.355000C23.693001,94.403999 36.193001,100.000000 50.000000,100.000000c11.935000,0.000000 22.886999,-4.187000 31.482000,-11.164000C61.909000,100.523003 36.202999,96.495003 21.250000,78.369003z"
- android:fillColor="#F06292"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/qs_subhead_caret.xml b/packages/SystemUI/res/drawable/qs_subhead_caret.xml
deleted file mode 100644
index 13a168d758aa..000000000000
--- a/packages/SystemUI/res/drawable/qs_subhead_caret.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="@color/qs_subhead"
- android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/quick_header_bg.xml b/packages/SystemUI/res/drawable/quick_header_bg.xml
deleted file mode 100644
index 920e6f5ef086..000000000000
--- a/packages/SystemUI/res/drawable/quick_header_bg.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight" >
- <item android:drawable="?android:attr/colorPrimary"/>
-</ripple>
diff --git a/packages/SystemUI/res/drawable/scorecard_gameover.xml b/packages/SystemUI/res/drawable/scorecard_gameover.xml
deleted file mode 100644
index f663a661f3f1..000000000000
--- a/packages/SystemUI/res/drawable/scorecard_gameover.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle"
- >
- <corners
- android:radius="8dp" />
- <solid
- android:color="#ffff0000" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/stat_notify_more.xml b/packages/SystemUI/res/drawable/stat_notify_more.xml
deleted file mode 100644
index 50f12861afe8..000000000000
--- a/packages/SystemUI/res/drawable/stat_notify_more.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M22.000000,3.000000L7.000000,3.000000C6.300000,3.000000 5.800000,3.400000 5.400000,3.900000L0.000000,12.000000l5.400000,8.100000c0.400000,0.500000 1.000000,0.900000 1.700000,0.900000L22.000000,21.000000c1.100000,0.000000 2.000000,-0.900000 2.000000,-2.000000L24.000000,5.000000C24.000000,3.900000 23.100000,3.000000 22.000000,3.000000zM9.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S9.800000,13.500000 9.000000,13.500000zM14.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S14.800000,13.500000 14.000000,13.500000zM19.000000,13.500000c-0.800000,0.000000 -1.500000,-0.700000 -1.500000,-1.500000s0.700000,-1.500000 1.500000,-1.500000c0.800000,0.000000 1.500000,0.700000 1.500000,1.500000S19.799999,13.500000 19.000000,13.500000z"
- android:fillColor="#FFFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
deleted file mode 100644
index ba0709e9aa0e..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:height="17dp"
- android:width="17dp"
- android:viewportHeight="48"
- android:viewportWidth="48" >
- <group
- android:name="ic_screen_rotation_48px_outlines"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="ic_screen_rotation_48px_outlines_pivot"
- android:translateX="-24.15"
- android:translateY="-24.25" >
- <group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- <group
- android:name="device"
- android:translateX="24.14999"
- android:translateY="24.25" >
- <path
- android:name="body"
- android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- </group>
- </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
deleted file mode 100644
index 46a1f3575f86..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp">
- <vector
- android:height="17dp"
- android:width="17dp"
- android:viewportHeight="48"
- android:viewportWidth="48" >
- <group
- android:name="icon"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="icon_pivot"
- android:translateX="-24.15"
- android:translateY="-24.25" >
- <group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- <group
- android:name="device"
- android:translateX="24.14999"
- android:translateY="24.25" >
- <path
- android:name="device_1"
- android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- </group>
- </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml
deleted file mode 100644
index 1dedd5d4daef..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status_off.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="23dp"
- android:height="18dp"
- android:viewportWidth="23.0"
- android:viewportHeight="18.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M19.4,16.6l-1.1,-1.1L8,5L5.1,2.2L4.2,3.1l2,2H5.7c-0.8,0 -1.4,0.6 -1.4,1.4v8c0,0.8 0.6,1.4 1.4,1.4h11.4l1.5,1.5L19.4,16.6zM18.7,6.5c0,-0.8 -0.6,-1.4 -1.4,-1.4h-2.9V3.6c0,-0.8 -0.6,-1.4 -1.4,-1.4h-3C9.2,2.1 8.6,2.8 8.6,3.6v0.2L18.7,14C18.7,14 18.7,6.5 18.7,6.5zM12.9,5.1H10V3.6h2.9V5.1z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml b/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
deleted file mode 100644
index 5c9be5c50a13..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h6v-3h2V9H12.09zM20,13h-2v3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H20V13z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
deleted file mode 100644
index 7e6e09b9c846..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:name="in"
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
deleted file mode 100644
index b7b6f0f56749..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:name="in"
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
- <path
- android:name="out"
- android:fillColor="#FFFFFFFF"
- android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
deleted file mode 100644
index 910c0355f5a9..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:name="out"
- android:fillColor="#FFFFFFFF"
- android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
deleted file mode 100644
index ba3d4e60c6e7..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="16.25dp"
- android:height="15dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:name="in"
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
deleted file mode 100644
index 1f3b68fd5d72..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="16.25dp"
- android:height="15dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:name="in"
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
- <path
- android:name="out"
- android:fillColor="#FFFFFFFF"
- android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
deleted file mode 100644
index 24c6b1e871fa..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="16.25dp"
- android:height="15dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:name="out"
- android:fillColor="#FFFFFFFF"
- android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/sun2.xml b/packages/SystemUI/res/drawable/sun2.xml
deleted file mode 100644
index 6d2d5041f5ab..000000000000
--- a/packages/SystemUI/res/drawable/sun2.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:pathData="M40.000000,17.400000L40.000000,8.000000l-9.400000,0.000000L24.000000,1.400000L17.400000,8.000000L8.000000,8.000000l0.000000,9.400000L1.400000,24.000000L8.000000,30.600000L8.000000,40.000000l9.400000,0.000000l6.600000,6.600000l6.600000,-6.600000L40.000000,40.000000l0.000000,-9.400000l6.600000,-6.600000L40.000000,17.400000zM24.000000,36.000000c-6.600000,0.000000 -12.000000,-5.400000 -12.000000,-12.000000s5.400000,-12.000000 12.000000,-12.000000c6.600000,0.000000 12.000000,5.400000 12.000000,12.000000S30.600000,36.000000 24.000000,36.000000zM24.000000,16.000000c-4.400000,0.000000 -8.000000,3.600000 -8.000000,8.000000c0.000000,4.400000 3.600000,8.000000 8.000000,8.000000s8.000000,-3.600000 8.000000,-8.000000C32.000000,19.600000 28.400000,16.000000 24.000000,16.000000z"
- android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
deleted file mode 100644
index 996ac5e030da..000000000000
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" >
- <solid android:color="?android:attr/colorBackgroundFloating" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index b3567f892c44..d5f29badd893 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -130,6 +130,7 @@
<!-- Biometric dialog colors -->
<color name="biometric_dialog_dim_color">#80000000</color> <!-- 50% black -->
+ <color name="biometric_face_icon_gray">#ffbdc1c6</color>
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6037dfc5154d..06df0e763498 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -861,9 +861,6 @@
<dimen name="bottom_padding">48dp</dimen>
<dimen name="edge_margin">8dp</dimen>
- <dimen name="rounded_corner_radius">@*android:dimen/rounded_corner_radius</dimen>
- <dimen name="rounded_corner_radius_top">@*android:dimen/rounded_corner_radius_top</dimen>
- <dimen name="rounded_corner_radius_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java
new file mode 100644
index 000000000000..51fcb0a841ca
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system;
+
+import android.content.Context;
+
+/**
+ * Wraps a context to expose some methods for launcher to call.
+ */
+public class ContextCompat {
+ private final Context mWrapped;
+
+ public ContextCompat(Context context) {
+ mWrapped = context;
+ }
+
+ public int getUserId() {
+ return mWrapped.getUserId();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 874cdccb8794..6864ea185834 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -48,14 +48,14 @@ import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 08fa434643f4..3cc9bb6f668f 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -38,6 +38,7 @@ import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.power.EnhancedEstimates;
@@ -45,7 +46,7 @@ import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.DisplayNavigationBarController;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -64,6 +65,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
@@ -79,7 +81,6 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
@@ -156,6 +157,12 @@ public class Dependency extends SystemUI {
public static final String LEAK_REPORT_EMAIL_NAME = "leak_report_email";
/**
+ * Whether this platform supports long-pressing notifications to show notification channel
+ * settings.
+ */
+ public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress";
+
+ /**
* Key for getting a background Looper for background work.
*/
public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME);
@@ -244,7 +251,7 @@ public class Dependency extends SystemUI {
@Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
@Inject Lazy<InitController> mInitController;
@Inject Lazy<AppOpsController> mAppOpsController;
- @Inject Lazy<DisplayNavigationBarController> mDisplayNavigationBarController;
+ @Inject Lazy<NavigationBarController> mNavigationBarController;
@Inject Lazy<StatusBarStateController> mStatusBarStateController;
@Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
@Inject Lazy<NotificationGroupAlertTransferHelper> mNotificationGroupAlertTransferHelper;
@@ -270,6 +277,8 @@ public class Dependency extends SystemUI {
@Inject
Lazy<NotificationAlertingManager> mNotificationAlertingManager;
@Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
+ @Inject Lazy<AutoHideController> mAutoHideController;
+ @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
@Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
@Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
@Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
@@ -410,8 +419,7 @@ public class Dependency extends SystemUI {
mProviders.put(AppOpsController.class, mAppOpsController::get);
- mProviders.put(DisplayNavigationBarController.class,
- mDisplayNavigationBarController::get);
+ mProviders.put(NavigationBarController.class, mNavigationBarController::get);
mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
mProviders.put(NotificationLockscreenUserManager.class,
@@ -443,6 +451,14 @@ public class Dependency extends SystemUI {
mProviders.put(BubbleController.class, mBubbleController::get);
mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get);
+ mProviders.put(ForegroundServiceNotificationListener.class,
+ mForegroundServiceNotificationListener::get);
+
+ // TODO(b/118592525): to support multi-display , we start to add something which is
+ // per-display, while others may be global. I think it's time to add
+ // a new class maybe named DisplayDependency to solve per-display
+ // Dependency problem.
+ mProviders.put(AutoHideController.class, mAutoHideController::get);
sDependency = this;
}
@@ -512,6 +528,9 @@ public class Dependency extends SystemUI {
public static void initDependencies(Context context) {
if (sDependency != null) return;
Dependency d = new Dependency();
+ SystemUIFactory.getInstance().getRootComponent()
+ .createDependency()
+ .createSystemUI(d);
d.mContext = context;
d.mComponents = new HashMap<>();
d.start();
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index b93a5fd1f761..f324a05bafff 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -19,6 +19,7 @@ package com.android.systemui;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.power.PowerNotificationWarnings;
import com.android.systemui.power.PowerUI;
@@ -37,7 +38,6 @@ import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastControllerImpl;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.ExtensionController;
@@ -219,12 +219,6 @@ public abstract class DependencyBinder {
/**
*/
@Binds
- public abstract ForegroundServiceController provideForegroundService(
- ForegroundServiceControllerImpl controllerImpl);
-
- /**
- */
- @Binds
public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index 2b521c53a1e6..88e32cbeaa29 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -41,9 +41,9 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.plugins.PluginInitializerImpl;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -139,12 +139,6 @@ public class DependencyProvider {
@Singleton
@Provides
- public ShadeController provideShadeController(Context context) {
- return SysUiServiceProvider.getComponent(context, StatusBar.class);
- }
-
- @Singleton
- @Provides
public SensorPrivacyManager provideSensorPrivacyManager(Context context) {
return context.getSystemService(SensorPrivacyManager.class);
}
@@ -170,7 +164,21 @@ public class DependencyProvider {
@Singleton
@Provides
+ public NavigationBarController provideNavigationBarController(Context context,
+ @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ return new NavigationBarController(context, mainHandler);
+ }
+
+ @Singleton
+ @Provides
public ConfigurationController provideConfigurationController(Context context) {
return new ConfigurationControllerImpl(context);
}
+
+ @Singleton
+ @Provides
+ public AutoHideController provideAutoHideController(Context context,
+ @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+ return new AutoHideController(context, mainHandler);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index ae6ee2af29fd..df0d7872bc61 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -15,65 +15,158 @@
package com.android.systemui;
import android.annotation.Nullable;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
+import android.util.SparseArray;
-public interface ForegroundServiceController {
- /**
- * @param sbn notification that was just posted
- * @param importance
- */
- void addNotification(StatusBarNotification sbn, int importance);
+import com.android.internal.messages.nano.SystemMessageProto;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Tracks state of foreground services and notifications related to foreground services per user.
+ */
+@Singleton
+public class ForegroundServiceController {
+
+ private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
+ private final Object mMutex = new Object();
+
+ @Inject
+ public ForegroundServiceController() {
+ }
/**
- * @param sbn notification that was just changed in some way
- * @param newImportance
+ * @return true if this user has services missing notifications and therefore needs a
+ * disclosure notification.
*/
- void updateNotification(StatusBarNotification sbn, int newImportance);
+ public boolean isDisclosureNeededForUser(int userId) {
+ synchronized (mMutex) {
+ final ForegroundServicesUserState services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.isDisclosureNeeded();
+ }
+ }
/**
- * @param sbn notification that was just canceled
+ * @return true if this user/pkg has a missing or custom layout notification and therefore needs
+ * a disclosure notification for system alert windows.
*/
- boolean removeNotification(StatusBarNotification sbn);
+ public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
+ synchronized (mMutex) {
+ final ForegroundServicesUserState services = mUserServices.get(userId);
+ if (services == null) return false;
+ return services.getStandardLayoutKey(pkg) == null;
+ }
+ }
/**
- * @param userId
- * @return true if this user has services missing notifications and therefore needs a
- * disclosure notification.
+ * Returns the key of the foreground service from this package using the standard template,
+ * if one exists.
*/
- boolean isDungeonNeededForUser(int userId);
+ @Nullable
+ public String getStandardLayoutKey(int userId, String pkg) {
+ synchronized (mMutex) {
+ final ForegroundServicesUserState services = mUserServices.get(userId);
+ if (services == null) return null;
+ return services.getStandardLayoutKey(pkg);
+ }
+ }
/**
- * @param sbn
- * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
+ * Gets active app ops for this user and package
*/
- boolean isDungeonNotification(StatusBarNotification sbn);
+ @Nullable
+ public ArraySet<Integer> getAppOps(int userId, String pkg) {
+ synchronized (mMutex) {
+ final ForegroundServicesUserState services = mUserServices.get(userId);
+ if (services == null) {
+ return null;
+ }
+ return services.getFeatures(pkg);
+ }
+ }
/**
- * @return true if sbn is one of the window manager "drawing over other apps" notifications
+ * Records active app ops. App Ops are stored in FSC in addition to NotificationData in
+ * case they change before we have a notification to tag.
*/
- boolean isSystemAlertNotification(StatusBarNotification sbn);
+ public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
+ int userId = UserHandle.getUserId(uid);
+ synchronized (mMutex) {
+ ForegroundServicesUserState userServices = mUserServices.get(userId);
+ if (userServices == null) {
+ userServices = new ForegroundServicesUserState();
+ mUserServices.put(userId, userServices);
+ }
+ if (active) {
+ userServices.addOp(packageName, code);
+ } else {
+ userServices.removeOp(packageName, code);
+ }
+ }
+ }
/**
- * Returns the key of the foreground service from this package using the standard template,
- * if one exists.
+ * Looks up the {@link ForegroundServicesUserState} for the given {@code userId}, then performs
+ * the given {@link UserStateUpdateCallback} on it. If no state exists for the user ID, creates
+ * a new one if {@code createIfNotFound} is true, then performs the update on the new state.
+ * If {@code createIfNotFound} is false, no update is performed.
+ *
+ * @return false if no user state was found and none was created; true otherwise.
*/
- @Nullable String getStandardLayoutKey(int userId, String pkg);
+ boolean updateUserState(int userId,
+ UserStateUpdateCallback updateCallback,
+ boolean createIfNotFound) {
+ synchronized (mMutex) {
+ ForegroundServicesUserState userState = mUserServices.get(userId);
+ if (userState == null) {
+ if (createIfNotFound) {
+ userState = new ForegroundServicesUserState();
+ mUserServices.put(userId, userState);
+ } else {
+ return false;
+ }
+ }
+ return updateCallback.updateUserState(userState);
+ }
+ }
/**
- * @return true if this user/pkg has a missing or custom layout notification and therefore needs
- * a disclosure notification for system alert windows.
+ * @return true if {@code sbn} is the system-provided disclosure notification containing the
+ * list of running foreground services.
*/
- boolean isSystemAlertWarningNeeded(int userId, String pkg);
+ public boolean isDisclosureNotification(StatusBarNotification sbn) {
+ return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
+ && sbn.getTag() == null
+ && sbn.getPackageName().equals("android");
+ }
/**
- * Records active app ops. App Ops are stored in FSC in addition to NotificationData in
- * case they change before we have a notification to tag.
+ * @return true if sbn is one of the window manager "drawing over other apps" notifications
*/
- void onAppOpChanged(int code, int uid, String packageName, boolean active);
+ public boolean isSystemAlertNotification(StatusBarNotification sbn) {
+ return sbn.getPackageName().equals("android")
+ && sbn.getTag() != null
+ && sbn.getTag().contains("AlertWindowNotification");
+ }
/**
- * Gets active app ops for this user and package
+ * Callback provided to {@link #updateUserState(int, UserStateUpdateCallback, boolean)}
+ * to perform the update.
*/
- @Nullable ArraySet<Integer> getAppOps(int userId, String packageName);
+ interface UserStateUpdateCallback {
+ /**
+ * Perform update operations on the provided {@code userState}.
+ *
+ * @return true if the update succeeded.
+ */
+ boolean updateUserState(ForegroundServicesUserState userState);
+
+ /** Called if the state was not found and was not created. */
+ default void userStateNotFound(int userId) {
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
deleted file mode 100644
index ae446ddc91ab..000000000000
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.messages.nano.SystemMessageProto;
-
-import java.util.Arrays;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Foreground service controller, a/k/a Dianne's Dungeon.
- */
-@Singleton
-public class ForegroundServiceControllerImpl
- implements ForegroundServiceController {
-
- // shelf life of foreground services before they go bad
- public static final long FG_SERVICE_GRACE_MILLIS = 5000;
-
- private static final String TAG = "FgServiceController";
- private static final boolean DBG = false;
-
- private final Context mContext;
- private final SparseArray<UserServices> mUserServices = new SparseArray<>();
- private final Object mMutex = new Object();
-
- @Inject
- public ForegroundServiceControllerImpl(Context context) {
- mContext = context;
- }
-
- @Override
- public boolean isDungeonNeededForUser(int userId) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return false;
- return services.isDungeonNeeded();
- }
- }
-
- @Override
- public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return false;
- return services.getStandardLayoutKey(pkg) == null;
- }
- }
-
- @Override
- public String getStandardLayoutKey(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) return null;
- return services.getStandardLayoutKey(pkg);
- }
- }
-
- @Override
- public ArraySet<Integer> getAppOps(int userId, String pkg) {
- synchronized (mMutex) {
- final UserServices services = mUserServices.get(userId);
- if (services == null) {
- return null;
- }
- return services.getFeatures(pkg);
- }
- }
-
- @Override
- public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
- int userId = UserHandle.getUserId(uid);
- synchronized (mMutex) {
- UserServices userServices = mUserServices.get(userId);
- if (userServices == null) {
- userServices = new UserServices();
- mUserServices.put(userId, userServices);
- }
- if (active) {
- userServices.addOp(packageName, code);
- } else {
- userServices.removeOp(packageName, code);
- }
- }
- }
-
- @Override
- public void addNotification(StatusBarNotification sbn, int importance) {
- updateNotification(sbn, importance);
- }
-
- @Override
- public boolean removeNotification(StatusBarNotification sbn) {
- synchronized (mMutex) {
- final UserServices userServices = mUserServices.get(sbn.getUserId());
- if (userServices == null) {
- if (DBG) {
- Log.w(TAG, String.format(
- "user %d with no known notifications got removeNotification for %s",
- sbn.getUserId(), sbn));
- }
- return false;
- }
- if (isDungeonNotification(sbn)) {
- // if you remove the dungeon entirely, we take that to mean there are
- // no running services
- userServices.setRunningServices(null, 0);
- return true;
- } else {
- // this is safe to call on any notification, not just FLAG_FOREGROUND_SERVICE
- return userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
- }
- }
- }
-
- @Override
- public void updateNotification(StatusBarNotification sbn, int newImportance) {
- synchronized (mMutex) {
- UserServices userServices = mUserServices.get(sbn.getUserId());
- if (userServices == null) {
- userServices = new UserServices();
- mUserServices.put(sbn.getUserId(), userServices);
- }
-
- if (isDungeonNotification(sbn)) {
- final Bundle extras = sbn.getNotification().extras;
- if (extras != null) {
- final String[] svcs = extras.getStringArray(Notification.EXTRA_FOREGROUND_APPS);
- userServices.setRunningServices(svcs, sbn.getNotification().when);
- }
- } else {
- userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
- if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)) {
- if (newImportance > NotificationManager.IMPORTANCE_MIN) {
- userServices.addImportantNotification(sbn.getPackageName(), sbn.getKey());
- }
- final Notification.Builder builder = Notification.Builder.recoverBuilder(
- mContext, sbn.getNotification());
- if (builder.usesStandardHeader()) {
- userServices.addStandardLayoutNotification(
- sbn.getPackageName(), sbn.getKey());
- }
- }
- }
- }
- }
-
- @Override
- public boolean isDungeonNotification(StatusBarNotification sbn) {
- return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
- && sbn.getTag() == null
- && sbn.getPackageName().equals("android");
- }
-
- @Override
- public boolean isSystemAlertNotification(StatusBarNotification sbn) {
- return sbn.getPackageName().equals("android")
- && sbn.getTag() != null
- && sbn.getTag().contains("AlertWindowNotification");
- }
-
- /**
- * Struct to track relevant packages and notifications for a userid's foreground services.
- */
- private static class UserServices {
- private String[] mRunning = null;
- private long mServiceStartTime = 0;
- // package -> sufficiently important posted notification keys
- private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
- // package -> standard layout posted notification keys
- private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
-
- // package -> app ops
- private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
-
- public void setRunningServices(String[] pkgs, long serviceStartTime) {
- mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
- mServiceStartTime = serviceStartTime;
- }
-
- public void addOp(String pkg, int op) {
- if (mAppOps.get(pkg) == null) {
- mAppOps.put(pkg, new ArraySet<>(3));
- }
- mAppOps.get(pkg).add(op);
- }
-
- public boolean removeOp(String pkg, int op) {
- final boolean found;
- final ArraySet<Integer> keys = mAppOps.get(pkg);
- if (keys == null) {
- found = false;
- } else {
- found = keys.remove(op);
- if (keys.size() == 0) {
- mAppOps.remove(pkg);
- }
- }
- return found;
- }
-
- public void addImportantNotification(String pkg, String key) {
- addNotification(mImportantNotifications, pkg, key);
- }
-
- public boolean removeImportantNotification(String pkg, String key) {
- return removeNotification(mImportantNotifications, pkg, key);
- }
-
- public void addStandardLayoutNotification(String pkg, String key) {
- addNotification(mStandardLayoutNotifications, pkg, key);
- }
-
- public boolean removeStandardLayoutNotification(String pkg, String key) {
- return removeNotification(mStandardLayoutNotifications, pkg, key);
- }
-
- public boolean removeNotification(String pkg, String key) {
- boolean removed = false;
- removed |= removeImportantNotification(pkg, key);
- removed |= removeStandardLayoutNotification(pkg, key);
- return removed;
- }
-
- public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
- String key) {
- if (map.get(pkg) == null) {
- map.put(pkg, new ArraySet<>());
- }
- map.get(pkg).add(key);
- }
-
- public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
- String pkg, String key) {
- final boolean found;
- final ArraySet<String> keys = map.get(pkg);
- if (keys == null) {
- found = false;
- } else {
- found = keys.remove(key);
- if (keys.size() == 0) {
- map.remove(pkg);
- }
- }
- return found;
- }
-
- public boolean isDungeonNeeded() {
- if (mRunning != null
- && System.currentTimeMillis() - mServiceStartTime >= FG_SERVICE_GRACE_MILLIS) {
-
- for (String pkg : mRunning) {
- final ArraySet<String> set = mImportantNotifications.get(pkg);
- if (set == null || set.size() == 0) {
- return true;
- }
- }
- }
- return false;
- }
-
- public ArraySet<Integer> getFeatures(String pkg) {
- return mAppOps.get(pkg);
- }
-
- public String getStandardLayoutKey(String pkg) {
- final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
- if (set == null || set.size() == 0) {
- return null;
- }
- return set.valueAt(0);
- }
-
- @Override
- public String toString() {
- return "UserServices{" +
- "mRunning=" + Arrays.toString(mRunning) +
- ", mServiceStartTime=" + mServiceStartTime +
- ", mImportantNotifications=" + mImportantNotifications +
- ", mStandardLayoutNotifications=" + mStandardLayoutNotifications +
- '}';
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
new file mode 100644
index 000000000000..b0b7e6c88984
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Updates foreground service notification state in response to notification data events. */
+@Singleton
+public class ForegroundServiceNotificationListener {
+
+ private static final String TAG = "FgServiceController";
+ private static final boolean DBG = false;
+
+ private final Context mContext;
+ private final ForegroundServiceController mForegroundServiceController;
+
+ @Inject
+ public ForegroundServiceNotificationListener(Context context,
+ ForegroundServiceController foregroundServiceController,
+ NotificationEntryManager notificationEntryManager) {
+ mContext = context;
+ mForegroundServiceController = foregroundServiceController;
+ notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationData.Entry entry) {
+ addNotification(entry.notification, entry.importance);
+ }
+
+ @Override
+ public void onEntryUpdated(NotificationData.Entry entry) {
+ updateNotification(entry.notification, entry.importance);
+ }
+
+ @Override
+ public void onEntryRemoved(
+ NotificationData.Entry entry,
+ NotificationVisibility visibility,
+ boolean removedByUser) {
+ removeNotification(entry.notification);
+ }
+ });
+ }
+
+ /**
+ * @param sbn notification that was just posted
+ */
+ private void addNotification(StatusBarNotification sbn, int importance) {
+ updateNotification(sbn, importance);
+ }
+
+ /**
+ * @param sbn notification that was just removed
+ */
+ private void removeNotification(StatusBarNotification sbn) {
+ mForegroundServiceController.updateUserState(
+ sbn.getUserId(),
+ new ForegroundServiceController.UserStateUpdateCallback() {
+ @Override
+ public boolean updateUserState(ForegroundServicesUserState userState) {
+ if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+ // if you remove the dungeon entirely, we take that to mean there are
+ // no running services
+ userState.setRunningServices(null, 0);
+ return true;
+ } else {
+ // this is safe to call on any notification, not just
+ // FLAG_FOREGROUND_SERVICE
+ return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+ }
+ }
+
+ @Override
+ public void userStateNotFound(int userId) {
+ if (DBG) {
+ Log.w(TAG, String.format(
+ "user %d with no known notifications got removeNotification "
+ + "for %s",
+ sbn.getUserId(), sbn));
+ }
+ }
+ },
+ false /* don't create */);
+ }
+
+ /**
+ * @param sbn notification that was just changed in some way
+ */
+ private void updateNotification(StatusBarNotification sbn, int newImportance) {
+ mForegroundServiceController.updateUserState(
+ sbn.getUserId(),
+ userState -> {
+ if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+ final Bundle extras = sbn.getNotification().extras;
+ if (extras != null) {
+ final String[] svcs = extras.getStringArray(
+ Notification.EXTRA_FOREGROUND_APPS);
+ userState.setRunningServices(svcs, sbn.getNotification().when);
+ }
+ } else {
+ userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+ if (0 != (sbn.getNotification().flags
+ & Notification.FLAG_FOREGROUND_SERVICE)) {
+ if (newImportance > NotificationManager.IMPORTANCE_MIN) {
+ userState.addImportantNotification(sbn.getPackageName(),
+ sbn.getKey());
+ }
+ final Notification.Builder builder =
+ Notification.Builder.recoverBuilder(
+ mContext, sbn.getNotification());
+ if (builder.usesStandardHeader()) {
+ userState.addStandardLayoutNotification(
+ sbn.getPackageName(), sbn.getKey());
+ }
+ }
+ }
+ return true;
+ },
+ true /* create if not found */);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
new file mode 100644
index 000000000000..a8ae65490b28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Arrays;
+
+/**
+ * Struct to track relevant packages and notifications for a userid's foreground services.
+ */
+class ForegroundServicesUserState {
+ // shelf life of foreground services before they go bad
+ private static final long FG_SERVICE_GRACE_MILLIS = 5000;
+
+ private String[] mRunning = null;
+ private long mServiceStartTime = 0;
+ // package -> sufficiently important posted notification keys
+ private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
+ // package -> standard layout posted notification keys
+ private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
+
+ // package -> app ops
+ private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
+
+ public void setRunningServices(String[] pkgs, long serviceStartTime) {
+ mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
+ mServiceStartTime = serviceStartTime;
+ }
+
+ public void addOp(String pkg, int op) {
+ if (mAppOps.get(pkg) == null) {
+ mAppOps.put(pkg, new ArraySet<>(3));
+ }
+ mAppOps.get(pkg).add(op);
+ }
+
+ public boolean removeOp(String pkg, int op) {
+ final boolean found;
+ final ArraySet<Integer> keys = mAppOps.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(op);
+ if (keys.size() == 0) {
+ mAppOps.remove(pkg);
+ }
+ }
+ return found;
+ }
+
+ public void addImportantNotification(String pkg, String key) {
+ addNotification(mImportantNotifications, pkg, key);
+ }
+
+ public boolean removeImportantNotification(String pkg, String key) {
+ return removeNotification(mImportantNotifications, pkg, key);
+ }
+
+ public void addStandardLayoutNotification(String pkg, String key) {
+ addNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeStandardLayoutNotification(String pkg, String key) {
+ return removeNotification(mStandardLayoutNotifications, pkg, key);
+ }
+
+ public boolean removeNotification(String pkg, String key) {
+ boolean removed = false;
+ removed |= removeImportantNotification(pkg, key);
+ removed |= removeStandardLayoutNotification(pkg, key);
+ return removed;
+ }
+
+ public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
+ String key) {
+ if (map.get(pkg) == null) {
+ map.put(pkg, new ArraySet<>());
+ }
+ map.get(pkg).add(key);
+ }
+
+ public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
+ String pkg, String key) {
+ final boolean found;
+ final ArraySet<String> keys = map.get(pkg);
+ if (keys == null) {
+ found = false;
+ } else {
+ found = keys.remove(key);
+ if (keys.size() == 0) {
+ map.remove(pkg);
+ }
+ }
+ return found;
+ }
+
+ public boolean isDisclosureNeeded() {
+ if (mRunning != null
+ && System.currentTimeMillis() - mServiceStartTime
+ >= FG_SERVICE_GRACE_MILLIS) {
+
+ for (String pkg : mRunning) {
+ final ArraySet<String> set = mImportantNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public ArraySet<Integer> getFeatures(String pkg) {
+ return mAppOps.get(pkg);
+ }
+
+ public String getStandardLayoutKey(String pkg) {
+ final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
+ if (set == null || set.size() == 0) {
+ return null;
+ }
+ return set.valueAt(0);
+ }
+
+ @Override
+ public String toString() {
+ return "UserServices{"
+ + "mRunning=" + Arrays.toString(mRunning)
+ + ", mServiceStartTime=" + mServiceStartTime
+ + ", mImportantNotifications=" + mImportantNotifications
+ + ", mStandardLayoutNotifications=" + mStandardLayoutNotifications
+ + '}';
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 1dd231ca7642..ab077d636beb 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -329,11 +329,11 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private void updateRoundedCornerRadii() {
final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius);
+ com.android.internal.R.dimen.rounded_corner_radius);
final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius_top);
+ com.android.internal.R.dimen.rounded_corner_radius_top);
final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
- R.dimen.rounded_corner_radius_bottom);
+ com.android.internal.R.dimen.rounded_corner_radius_bottom);
final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
|| mRoundedDefaultBottom != newRoundedDefaultBottom
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index e3bfdc911941..5347a5cb16b6 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui;
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
import android.annotation.Nullable;
@@ -50,6 +51,7 @@ import com.android.systemui.statusbar.phone.LockscreenWallpaper;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ScrimState;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -200,6 +202,19 @@ public class SystemUIFactory {
return new NotificationInterruptionStateProvider(context);
}
+ @Singleton
+ @Provides
+ @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
+ public boolean provideAllowNotificationLongPress() {
+ return true;
+ }
+
+ @Singleton
+ @Provides
+ public ShadeController provideShadeController(Context context) {
+ return SysUiServiceProvider.getComponent(context, StatusBar.class);
+ }
+
@Module
protected static class ContextHolder {
private Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index ba89fe662a65..3167b9e0a458 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -240,7 +240,10 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
mConfirmShowing = true;
mCurrentDialog.showConfirmationButton(true /* show */);
} else {
- handleHideDialog(false /* userCanceled */);
+ mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
+ mHandler.postDelayed(() -> {
+ handleHideDialog(false /* userCanceled */);
+ }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index e085f2368214..9934bfd11f12 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
@@ -63,7 +64,8 @@ public abstract class BiometricDialogView extends LinearLayout {
protected static final int STATE_NONE = 0;
protected static final int STATE_AUTHENTICATING = 1;
protected static final int STATE_ERROR = 2;
- protected static final int STATE_AUTHENTICATED = 3;
+ protected static final int STATE_PENDING_CONFIRMATION = 3;
+ protected static final int STATE_AUTHENTICATED = 4;
private final IBinder mWindowToken = new Binder();
private final Interpolator mLinearOutSlowIn;
@@ -77,6 +79,8 @@ public abstract class BiometricDialogView extends LinearLayout {
private final DialogViewCallback mCallback;
private ViewGroup mLayout;
+ private final Button mPositiveButton;
+ private final Button mNegativeButton;
private final TextView mErrorText;
private Bundle mBundle;
private final LinearLayout mDialog;
@@ -90,10 +94,12 @@ public abstract class BiometricDialogView extends LinearLayout {
private boolean mPendingShowTryAgain;
private boolean mPendingShowConfirm;
- protected abstract void updateIcon(int lastState, int newState);
protected abstract int getHintStringResourceId();
protected abstract int getAuthenticatedAccessibilityResourceId();
protected abstract int getIconDescriptionResourceId();
+ protected abstract Drawable getAnimationForTransition(int oldState, int newState);
+ protected abstract boolean shouldAnimateForTransition(int oldState, int newState);
+ protected abstract int getDelayAfterAuthenticatedDurationMs();
private final Runnable mShowAnimationRunnable = new Runnable() {
@Override
@@ -178,10 +184,10 @@ public abstract class BiometricDialogView extends LinearLayout {
final View space = mLayout.findViewById(R.id.space);
final View leftSpace = mLayout.findViewById(R.id.left_space);
final View rightSpace = mLayout.findViewById(R.id.right_space);
- final Button negative = mLayout.findViewById(R.id.button2);
- final Button positive = mLayout.findViewById(R.id.button1);
final ImageView icon = mLayout.findViewById(R.id.biometric_icon);
final Button tryAgain = mLayout.findViewById(R.id.button_try_again);
+ mNegativeButton = mLayout.findViewById(R.id.button2);
+ mPositiveButton = mLayout.findViewById(R.id.button1);
icon.setContentDescription(getResources().getString(getIconDescriptionResourceId()));
@@ -189,12 +195,15 @@ public abstract class BiometricDialogView extends LinearLayout {
setDismissesDialog(leftSpace);
setDismissesDialog(rightSpace);
- negative.setOnClickListener((View v) -> {
+ mNegativeButton.setOnClickListener((View v) -> {
mCallback.onNegativePressed();
});
- positive.setOnClickListener((View v) -> {
- mCallback.onPositivePressed();
+ mPositiveButton.setOnClickListener((View v) -> {
+ updateState(STATE_AUTHENTICATED);
+ mHandler.postDelayed(() -> {
+ mCallback.onPositivePressed();
+ }, getDelayAfterAuthenticatedDurationMs());
});
tryAgain.setOnClickListener((View v) -> {
@@ -215,7 +224,6 @@ public abstract class BiometricDialogView extends LinearLayout {
final TextView title = mLayout.findViewById(R.id.title);
final TextView subtitle = mLayout.findViewById(R.id.subtitle);
final TextView description = mLayout.findViewById(R.id.description);
- final Button negative = mLayout.findViewById(R.id.button2);
final ImageView backgroundView = mLayout.findViewById(R.id.background);
if (mUserManager.isManagedProfile(mUserId)) {
@@ -229,6 +237,9 @@ public abstract class BiometricDialogView extends LinearLayout {
backgroundView.setBackgroundColor(R.color.biometric_dialog_dim_color);
}
+ mNegativeButton.setVisibility(View.VISIBLE);
+ mErrorText.setVisibility(View.VISIBLE);
+
if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
mDialog.getLayoutParams().width = (int) mDialogWidth;
}
@@ -258,7 +269,7 @@ public abstract class BiometricDialogView extends LinearLayout {
description.setText(descriptionText);
}
- negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
+ mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
showTryAgainButton(mPendingShowTryAgain);
showConfirmationButton(mPendingShowConfirm);
@@ -280,10 +291,32 @@ public abstract class BiometricDialogView extends LinearLayout {
mSkipIntro = false;
}
+ protected void updateIcon(int lastState, int newState) {
+ final Drawable icon = getAnimationForTransition(lastState, newState);
+ if (icon == null) {
+ Log.e(TAG, "Animation not found");
+ return;
+ }
+
+ final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
+ ? (AnimatedVectorDrawable) icon
+ : null;
+
+ final ImageView imageView = getLayout().findViewById(R.id.biometric_icon);
+ imageView.setImageDrawable(icon);
+
+ if (animation != null && shouldAnimateForTransition(lastState, newState)) {
+ animation.forceAnimationOnUI();
+ animation.start();
+ }
+ }
+
private void setDismissesDialog(View v) {
v.setClickable(true);
v.setOnTouchListener((View view, MotionEvent event) -> {
- mCallback.onUserCanceled();
+ if (mLastState != STATE_AUTHENTICATED) {
+ mCallback.onUserCanceled();
+ }
return true;
});
}
@@ -302,6 +335,7 @@ public abstract class BiometricDialogView extends LinearLayout {
showTryAgainButton(false /* show */);
mPendingShowTryAgain = false;
mPendingShowConfirm = false;
+ updateState(STATE_NONE);
}
};
@@ -362,11 +396,11 @@ public abstract class BiometricDialogView extends LinearLayout {
}
public void showConfirmationButton(boolean show) {
- final Button positive = mLayout.findViewById(R.id.button1);
if (show) {
- positive.setVisibility(View.VISIBLE);
+ updateState(STATE_PENDING_CONFIRMATION);
+ mPositiveButton.setVisibility(View.VISIBLE);
} else {
- positive.setVisibility(View.GONE);
+ mPositiveButton.setVisibility(View.GONE);
}
}
@@ -411,7 +445,15 @@ public abstract class BiometricDialogView extends LinearLayout {
mCallback.onErrorShown();
}
- private void updateState(int newState) {
+ public void updateState(int newState) {
+ if (newState == STATE_PENDING_CONFIRMATION) {
+ mErrorText.setVisibility(View.INVISIBLE);
+ } else if (newState == STATE_AUTHENTICATED) {
+ mPositiveButton.setVisibility(View.GONE);
+ mNegativeButton.setVisibility(View.GONE);
+ mErrorText.setVisibility(View.INVISIBLE);
+ }
+
updateIcon(mLastState, newState);
mLastState = newState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index feef3a6dc133..de3f9471a6ba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -18,16 +18,18 @@ package com.android.systemui.biometrics;
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
import com.android.systemui.R;
/**
* This class loads the view for the system-provided dialog. The view consists of:
- * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
+ * Application Icon, Title, Subtitle, Description, Biometric Icon, Error/Help message area,
* and positive/negative buttons.
*/
public class FaceDialogView extends BiometricDialogView {
+
+ private static final int HIDE_DIALOG_DELAY = 500; // ms
+
public FaceDialogView(Context context,
DialogViewCallback callback) {
super(context, callback);
@@ -53,10 +55,46 @@ public class FaceDialogView extends BiometricDialogView {
}
@Override
- protected void updateIcon(int lastState, int newState) {
- Drawable icon = mContext.getDrawable(R.drawable.face_dialog_icon);
+ protected boolean shouldAnimateForTransition(int oldState, int newState) {
+ if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+ return false;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
+ return true;
+ } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
+ return true;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_PENDING_CONFIRMATION) {
+ return true;
+ } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+ return true;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected int getDelayAfterAuthenticatedDurationMs() {
+ return HIDE_DIALOG_DELAY;
+ }
- final ImageView faceIcon = getLayout().findViewById(R.id.biometric_icon);
- faceIcon.setImageDrawable(icon);
+ @Override
+ protected Drawable getAnimationForTransition(int oldState, int newState) {
+ int iconRes;
+ if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+ iconRes = R.drawable.face_dialog_face_to_error;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
+ iconRes = R.drawable.face_dialog_face_to_error;
+ } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
+ iconRes = R.drawable.face_dialog_error_to_face;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_PENDING_CONFIRMATION) {
+ iconRes = R.drawable.face_dialog_face_gray_to_face_blue;
+ } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+ iconRes = R.drawable.face_dialog_face_blue_to_checkmark;
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+ iconRes = R.drawable.face_dialog_face_gray_to_checkmark;
+ } else {
+ return null;
+ }
+ return mContext.getDrawable(iconRes);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index 38a69a90f0bb..1a6cee281c84 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -17,21 +17,21 @@
package com.android.systemui.biometrics;
import android.content.Context;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.util.Log;
-import android.widget.ImageView;
import com.android.systemui.R;
/**
* This class loads the view for the system-provided dialog. The view consists of:
- * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
+ * Application Icon, Title, Subtitle, Description, Biometric Icon, Error/Help message area,
* and positive/negative buttons.
*/
public class FingerprintDialogView extends BiometricDialogView {
- private static final String TAG = "FingerprintDialogView";
+ public FingerprintDialogView(Context context,
+ DialogViewCallback callback) {
+ super(context, callback);
+ }
@Override
protected int getHintStringResourceId() {
return R.string.fingerprint_dialog_touch_sensor;
@@ -48,33 +48,7 @@ public class FingerprintDialogView extends BiometricDialogView {
}
@Override
- protected void updateIcon(int lastState, int newState) {
- Drawable icon = getAnimationForTransition(lastState, newState);
-
- if (icon == null) {
- Log.e(TAG, "Animation not found");
- return;
- }
-
- final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
- ? (AnimatedVectorDrawable) icon
- : null;
-
- final ImageView fingerprintIcon = getLayout().findViewById(R.id.biometric_icon);
- fingerprintIcon.setImageDrawable(icon);
-
- if (animation != null && shouldAnimateForTransition(lastState, newState)) {
- animation.forceAnimationOnUI();
- animation.start();
- }
- }
-
- public FingerprintDialogView(Context context,
- DialogViewCallback callback) {
- super(context, callback);
- }
-
- private boolean shouldAnimateForTransition(int oldState, int newState) {
+ protected boolean shouldAnimateForTransition(int oldState, int newState) {
if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
return false;
} else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
@@ -88,7 +62,13 @@ public class FingerprintDialogView extends BiometricDialogView {
return false;
}
- private Drawable getAnimationForTransition(int oldState, int newState) {
+ @Override
+ protected int getDelayAfterAuthenticatedDurationMs() {
+ return 0;
+ }
+
+ @Override
+ protected Drawable getAnimationForTransition(int oldState, int newState) {
int iconRes;
if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
iconRes = R.drawable.fingerprint_dialog_fp_to_error;
@@ -98,7 +78,7 @@ public class FingerprintDialogView extends BiometricDialogView {
iconRes = R.drawable.fingerprint_dialog_error_to_fp;
} else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
// TODO(b/77328470): add animation when fingerprint is authenticated
- iconRes = R.drawable.fingerprint_dialog_error_to_fp;
+ iconRes = R.drawable.fingerprint_dialog_fp_to_error;
} else {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 881aa18285ff..644723321103 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -33,8 +33,11 @@ import android.view.WindowManager;
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
import java.util.ArrayList;
@@ -57,47 +60,31 @@ public class BubbleController {
private static final String TAG = "BubbleController";
// Enables some subset of notifs to automatically become bubbles
- public static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
+ private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
// When a bubble is dismissed, recreate it as a notification
- public static final boolean DEBUG_DEMOTE_TO_NOTIF = false;
+ private static final boolean DEBUG_DEMOTE_TO_NOTIF = false;
// Secure settings
private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";
- private Context mContext;
- private BubbleDismissListener mDismissListener;
+ private final Context mContext;
+ private final NotificationEntryManager mNotificationEntryManager;
private BubbleStateChangeListener mStateChangeListener;
private BubbleExpandListener mExpandListener;
- private Map<String, BubbleView> mBubbles = new HashMap<>();
+ private final Map<String, BubbleView> mBubbles = new HashMap<>();
private BubbleStackView mStackView;
- private Point mDisplaySize;
+ private final Point mDisplaySize;
// Bubbles get added to the status bar view
- @VisibleForTesting
- protected StatusBarWindowController mStatusBarWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
// Used for determining view rect for touch interaction
private Rect mTempRect = new Rect();
/**
- * Listener to find out about bubble / bubble stack dismissal events.
- */
- public interface BubbleDismissListener {
- /**
- * Called when the entire stack of bubbles is dismissed by the user.
- */
- void onStackDismissed();
-
- /**
- * Called when a specific bubble is dismissed by the user.
- */
- void onBubbleDismissed(String key);
- }
-
- /**
* Listener to be notified when some states of the bubbles change.
*/
public interface BubbleStateChangeListener {
@@ -123,17 +110,13 @@ public class BubbleController {
@Inject
public BubbleController(Context context, StatusBarWindowController statusBarWindowController) {
mContext = context;
+ mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mDisplaySize = new Point();
wm.getDefaultDisplay().getSize(mDisplaySize);
mStatusBarWindowController = statusBarWindowController;
- }
- /**
- * Set a listener to be notified of bubble dismissal events.
- */
- public void setDismissListener(BubbleDismissListener listener) {
- mDismissListener = listener;
+ mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
}
/**
@@ -180,7 +163,7 @@ public class BubbleController {
/**
* Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
*/
- public void dismissStack() {
+ void dismissStack() {
if (mStackView == null) {
return;
}
@@ -190,9 +173,7 @@ public class BubbleController {
for (String key: mBubbles.keySet()) {
removeBubble(key);
}
- if (mDismissListener != null) {
- mDismissListener.onStackDismissed();
- }
+ mNotificationEntryManager.updateNotifications();
updateBubblesShowing();
}
@@ -238,18 +219,35 @@ public class BubbleController {
/**
* Removes the bubble associated with the {@param uri}.
*/
- public void removeBubble(String key) {
+ void removeBubble(String key) {
BubbleView bv = mBubbles.get(key);
if (mStackView != null && bv != null) {
mStackView.removeBubble(bv);
bv.getEntry().setBubbleDismissed(true);
}
- if (mDismissListener != null) {
- mDismissListener.onBubbleDismissed(key);
+
+ NotificationData.Entry entry = mNotificationEntryManager.getNotificationData().get(key);
+ if (entry != null) {
+ entry.setBubbleDismissed(true);
+ if (!DEBUG_DEMOTE_TO_NOTIF) {
+ mNotificationEntryManager.performRemoveNotification(entry.notification);
+ }
}
+ mNotificationEntryManager.updateNotifications();
+
updateBubblesShowing();
}
+ @SuppressWarnings("FieldCanBeLocal")
+ private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+ @Override
+ public void onPendingEntryAdded(NotificationData.Entry entry) {
+ if (shouldAutoBubble(mContext, entry)) {
+ entry.setIsBubble(true);
+ }
+ }
+ };
+
private void updateBubblesShowing() {
boolean hasBubblesShowing = false;
for (BubbleView bv : mBubbles.values()) {
@@ -309,7 +307,7 @@ public class BubbleController {
}
@VisibleForTesting
- public BubbleStackView getStackView() {
+ BubbleStackView getStackView() {
return mStackView;
}
@@ -317,7 +315,7 @@ public class BubbleController {
/**
* Gets an appropriate starting point to position the bubble stack.
*/
- public static Point getStartPoint(int size, Point displaySize) {
+ private static Point getStartPoint(int size, Point displaySize) {
final int x = displaySize.x - size + EDGE_OVERLAP;
final int y = displaySize.y / 4;
return new Point(x, y);
@@ -326,7 +324,7 @@ public class BubbleController {
/**
* Gets an appropriate position for the bubble when the stack is expanded.
*/
- public static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
+ static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
// Same place for now..
return new Point(EDGE_OVERLAP, size);
}
@@ -334,7 +332,7 @@ public class BubbleController {
/**
* Whether the notification should bubble or not.
*/
- public static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
+ private static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
if (entry.isBubbleDismissed()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index 47b56d08817d..fa5a114c7187 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -22,22 +22,22 @@ package com.android.systemui.dock;
public interface DockManager {
/**
- * Uninitialized / unknown dock states
+ * Uninitialized / undocking dock states
*/
int STATE_NONE = 0;
/**
* The state for docking
*/
- int STATE_DOCKING = 1;
+ int STATE_DOCKED = 1;
/**
- * The state for undocking
+ * The state for docking without showing UI
*/
- int STATE_UNDOCKING = 2;
+ int STATE_DOCKED_HIDE = 2;
/**
* Add a dock event listener into manager
*
- * @param callback A {@link DockEventListener} which want to add
+ * @param callback A {@link DockEventListener} which want to add
*/
void addListener(DockEventListener callback);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 8cd42c7711b8..9fc22340ea22 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -18,11 +18,13 @@ package com.android.systemui.doze;
import android.content.Context;
import android.os.Handler;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.DozeMachine.State;
import java.io.PrintWriter;
@@ -34,7 +36,6 @@ public class DozeDockHandler implements DozeMachine.Part {
private static final String TAG = "DozeDockHandler";
private static final boolean DEBUG = DozeService.DEBUG;
- private final Context mContext;
private final DozeMachine mMachine;
private final DozeHost mDozeHost;
private final AmbientDisplayConfiguration mConfig;
@@ -42,11 +43,10 @@ public class DozeDockHandler implements DozeMachine.Part {
private final DockEventListener mDockEventListener = new DockEventListener();
private final DockManager mDockManager;
- private boolean mDocking;
+ private int mDockState = DockManager.STATE_NONE;
public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
AmbientDisplayConfiguration config, Handler handler) {
- mContext = context;
mMachine = machine;
mDozeHost = dozeHost;
mConfig = config;
@@ -60,34 +60,35 @@ public class DozeDockHandler implements DozeMachine.Part {
case INITIALIZED:
mDockEventListener.register();
break;
- case DOZE:
case DOZE_AOD:
- mHandler.post(() -> requestPulse());
+ if (mDockState == DockManager.STATE_DOCKED_HIDE) {
+ mMachine.requestState(State.DOZE);
+ break;
+ }
+ // continue below
+ case DOZE:
+ if (mDockState == DockManager.STATE_DOCKED) {
+ mHandler.post(() -> requestPulse(newState));
+ }
break;
case FINISH:
mDockEventListener.unregister();
break;
default:
+ // no-op
}
}
- private void requestPulse() {
- if (!mDocking || mDozeHost.isPulsingBlocked() || !canPulse()) {
+ private void requestPulse(State dozeState) {
+ if (mDozeHost.isPulsingBlocked() || !dozeState.canPulse()) {
return;
}
mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING);
}
- private boolean canPulse() {
- return mMachine.getState() == DozeMachine.State.DOZE
- || mMachine.getState() == DozeMachine.State.DOZE_AOD;
- }
-
- private void requestPulseOutNow() {
- final DozeMachine.State state = mMachine.getState();
- if (state == DozeMachine.State.DOZE_PULSING
- || state == DozeMachine.State.DOZE_REQUEST_PULSE) {
+ private void requestPulseOutNow(State dozeState) {
+ if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING) {
final int pulseReason = mMachine.getPulseReason();
if (pulseReason == DozeLog.PULSE_REASON_DOCKING) {
mDozeHost.stopPulsing();
@@ -95,9 +96,14 @@ public class DozeDockHandler implements DozeMachine.Part {
}
}
+ private boolean isDocked() {
+ return mDockState == DockManager.STATE_DOCKED
+ || mDockState == DockManager.STATE_DOCKED_HIDE;
+ }
+
@Override
public void dump(PrintWriter pw) {
- pw.print(" DozeDockTriggers docking="); pw.println(mDocking);
+ pw.print(" DozeDockTriggers docking="); pw.println(isDocked());
}
private class DockEventListener implements DockManager.DockEventListener {
@@ -106,14 +112,21 @@ public class DozeDockHandler implements DozeMachine.Part {
@Override
public void onEvent(int event) {
if (DEBUG) Log.d(TAG, "dock event = " + event);
- switch (event) {
- case DockManager.STATE_DOCKING:
- mDocking = true;
- requestPulse();
+ final DozeMachine.State dozeState = mMachine.getState();
+ mDockState = event;
+ switch (mDockState) {
+ case DockManager.STATE_DOCKED:
+ requestPulse(dozeState);
break;
- case DockManager.STATE_UNDOCKING:
- mDocking = false;
- requestPulseOutNow();
+ case DockManager.STATE_NONE:
+ if (dozeState == State.DOZE
+ && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+ mMachine.requestState(State.DOZE_AOD);
+ break;
+ }
+ // continue below
+ case DockManager.STATE_DOCKED_HIDE:
+ requestPulseOutNow(dozeState);
break;
default:
// no-op
@@ -124,7 +137,6 @@ public class DozeDockHandler implements DozeMachine.Part {
if (mRegistered) {
return;
}
-
if (mDockManager != null) {
mDockManager.addListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 35b64ed35158..b6fc35553760 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -85,6 +85,7 @@ public class DozeSensors {
mProxCallback = proxCallback;
mResolver = mContext.getContentResolver();
+ boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
mSensors = new TriggerSensor[] {
new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
@@ -116,7 +117,7 @@ public class DozeSensors {
new PluginSensor(
new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
- mConfig.wakeScreenGestureAvailable(),
+ mConfig.wakeScreenGestureAvailable() && alwaysOn,
DozeLog.REASON_SENSOR_WAKE_UP,
false /* reports touch coordinates */,
false /* touchscreen */),
@@ -359,7 +360,9 @@ public class DozeSensors {
}
protected boolean enabledBySetting() {
- if (TextUtils.isEmpty(mSetting)) {
+ if (!mConfig.enabled(UserHandle.USER_CURRENT)) {
+ return false;
+ } else if (TextUtils.isEmpty(mSetting)) {
return true;
}
return Settings.Secure.getIntForUser(mResolver, mSetting, mSettingDefault ? 1 : 0,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 67aa82dc9688..76565649dd69 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -124,6 +124,7 @@ public class DozeUi implements DozeMachine.Part {
unscheduleTimeTick();
break;
case DOZE_REQUEST_PULSE:
+ scheduleTimeTick();
pulseWhileDozing(mMachine.getPulseReason());
break;
case INITIALIZED:
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index dc11b4c63d83..19a7ceaaaac3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -132,9 +132,9 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
}
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
- if (disabled == mDisabled) return;
+ if (displayId != mContext.getDisplayId() || disabled == mDisabled) return;
mDisabled = disabled;
if (disabled && mGlobalActions != null) {
mGlobalActions.dismissDialog();
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 3991c19e4d05..01ee5cabe5a0 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -50,6 +50,7 @@ class OngoingPrivacyDialog constructor(
object : DialogInterface.OnClickListener {
val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE)
+ @Suppress("DEPRECATION")
override fun onClick(dialog: DialogInterface?, which: Int) {
Dependency.get(ActivityStarter::class.java).startActivity(intent, false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index d5b807def21f..b218e80693b1 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -46,10 +46,13 @@ class PrivacyItemController(val context: Context, val callback: Callback) {
}
private var privacyList = emptyList<PrivacyItem>()
+ @Suppress("DEPRECATION")
private val appOpsController = Dependency.get(AppOpsController::class.java)
private val userManager = context.getSystemService(UserManager::class.java)
private var currentUserIds = emptyList<Int>()
+ @Suppress("DEPRECATION")
private val bgHandler = Handler(Dependency.get(Dependency.BG_LOOPER))
+ @Suppress("DEPRECATION")
private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
private var listening = false
val systemApp = PrivacyApplication(context.getString(R.string.device_services), context)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
index dfd3f735dfaa..2365e67fec2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
@@ -35,6 +35,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import javax.inject.Inject;
+
public class AutoAddTracker {
private static final String[][] CONVERT_PREFS = {
@@ -48,6 +50,7 @@ public class AutoAddTracker {
private final ArraySet<String> mAutoAdded;
private final Context mContext;
+ @Inject
public AutoAddTracker(Context context) {
mContext = context;
mAutoAdded = new ArraySet<>(getAdded());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 34d30fe58404..087a826844e2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -215,7 +215,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != getContext().getDisplayId()) {
+ return;
+ }
state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index d7d3981d05d1..7c937a944113 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -17,6 +17,7 @@ package com.android.systemui.qs;
import android.app.ActivityManager;
import android.app.AlertDialog;
+import android.app.admin.DevicePolicyEventLogger;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -30,6 +31,7 @@ import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.Log;
+import android.util.StatsLog;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
@@ -119,6 +121,9 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic
private void handleClick() {
showDeviceMonitoringDialog();
+ DevicePolicyEventLogger
+ .createEvent(StatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED)
+ .write();
}
public void showDeviceMonitoringDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 3a6b785eb9b5..dfc3e66d8d98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -56,6 +56,7 @@ import java.util.function.Predicate;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
import javax.inject.Singleton;
/** Platform implementation of the quick settings tile host **/
@@ -74,7 +75,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
private final PluginManager mPluginManager;
private final List<Callback> mCallbacks = new ArrayList<>();
- private final AutoTileManager mAutoTiles;
+ private AutoTileManager mAutoTiles;
private final StatusBarIconController mIconController;
private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();
private int mCurrentUser;
@@ -87,7 +88,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
@Named(Dependency.MAIN_HANDLER_NAME) Handler mainHandler,
@Named(Dependency.BG_LOOPER_NAME) Looper bgLooper,
PluginManager pluginManager,
- TunerService tunerService) {
+ TunerService tunerService,
+ Provider<AutoTileManager> autoTiles) {
mIconController = iconController;
mContext = context;
mTunerService = tunerService;
@@ -104,9 +106,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
// QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation
// finishes before creating any tiles.
tunerService.addTunable(this, TILES_SETTING);
+ // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
+ mAutoTiles = autoTiles.get();
});
- // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
- mAutoTiles = new AutoTileManager(context, this);
}
public StatusBarIconController getIconController() {
@@ -264,7 +266,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
@Override
public void unmarkTileAsAutoAdded(String spec) {
- mAutoTiles.unmarkTileAsAutoAdded(spec);
+ if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
}
public void addTile(String spec) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index bec027f902a0..72245999b084 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -63,6 +63,8 @@ import com.android.systemui.BatteryMeterView;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.privacy.OngoingPrivacyDialog;
import com.android.systemui.privacy.PrivacyItem;
@@ -75,8 +77,6 @@ import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index f13b565bd532..0fc4fe72bd54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -54,8 +54,10 @@ public class Recents extends SystemUI implements CommandQueue.Callbacks {
}
@Override
- public void appTransitionFinished() {
- mImpl.onAppTransitionFinished();
+ public void appTransitionFinished(int displayId) {
+ if (mContext.getDisplayId() == displayId) {
+ mImpl.onAppTransitionFinished();
+ }
}
public void growRecents() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 95019ee2aeea..6a015630a076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -16,18 +16,30 @@
package com.android.systemui.statusbar;
+import static android.app.StatusBarManager.DISABLE2_NONE;
+import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
import android.app.StatusBarManager;
+import android.app.StatusBarManager.Disable2Flags;
+import android.app.StatusBarManager.DisableFlags;
+import android.app.StatusBarManager.WindowType;
+import android.app.StatusBarManager.WindowVisibleState;
import android.content.ComponentName;
+import android.content.Context;
import android.graphics.Rect;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.display.DisplayManager;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Pair;
+import android.util.SparseArray;
import androidx.annotation.VisibleForTesting;
@@ -47,7 +59,8 @@ import java.util.ArrayList;
* coalescing these calls so they don't stack up. For the calls
* are coalesced, note that they are all idempotent.
*/
-public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks> {
+public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>,
+ DisplayManager.DisplayListener {
private static final int INDEX_MASK = 0xffff;
private static final int MSG_SHIFT = 16;
private static final int MSG_MASK = 0xffff << MSG_SHIFT;
@@ -112,8 +125,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
private final Object mLock = new Object();
private ArrayList<Callbacks> mCallbacks = new ArrayList<>();
private Handler mHandler = new H(Looper.getMainLooper());
- private int mDisable1;
- private int mDisable2;
+ /** A map of display id - disable flag pair */
+ private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
/**
* These methods are called back on the main thread.
@@ -121,17 +134,63 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
public interface Callbacks {
default void setIcon(String slot, StatusBarIcon icon) { }
default void removeIcon(String slot) { }
- default void disable(int state1, int state2, boolean animate) { }
+
+ /**
+ * Called to notify that disable flags are updated.
+ * @see IStatusBar#disable(int, int, int).
+ *
+ * @param displayId The id of the display to notify.
+ * @param state1 The combination of following DISABLE_* flags:
+ * @param state2 The combination of following DISABLE2_* flags:
+ * @param animate {@code true} to show animations.
+ */
+ default void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
+ boolean animate) { }
default void animateExpandNotificationsPanel() { }
default void animateCollapsePanels(int flags, boolean force) { }
default void togglePanel() { }
default void animateExpandSettingsPanel(String obj) { }
- default void setSystemUiVisibility(int vis, int fullscreenStackVis,
+
+ /**
+ * Called to notify visibility flag changes.
+ * @see IStatusBar#setSystemUiVisibility(int, int, int, int, int, Rect, Rect).
+ *
+ * @param displayId The id of the display to notify.
+ * @param vis The visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will
+ * be reported separately in fullscreenStackVis and dockedStackVis.
+ * @param fullscreenStackVis The flags which only apply in the region of the fullscreen
+ * stack, which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ * @param dockedStackVis The flags that only apply in the region of the docked stack, which
+ * is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ * @param mask Which flags to change.
+ * @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen
+ * coordinates.
+ * @param dockedStackBounds The current bounds of the docked stack, in screen coordinates.
+ */
+ default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
}
- default void topAppWindowChanged(boolean visible) { }
- default void setImeWindowStatus(IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) { }
+
+ /**
+ * Called to notify top app window changes.
+ * @see IStatusBar#topAppWindowChanged(int, boolean)
+ *
+ * @param displayId The id of the display to notify.
+ * @param visible {@code true} to show menu button.
+ */
+ default void topAppWindowChanged(int displayId, boolean visible) { }
+
+ /**
+ * Called to notify IME window status changes.
+ *
+ * @param displayId The id of the display to notify.
+ * @param token IME token.
+ * @param vis IME visibility.
+ * @param backDisposition Disposition mode of back button. It should be one of below flags:
+ * @param showImeSwitcher {@code true} to show IME switch button.
+ */
+ default void setImeWindowStatus(int displayId, IBinder token, int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleRecentApps() { }
@@ -140,12 +199,56 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
default void dismissKeyboardShortcutsMenu() { }
default void toggleKeyboardShortcutsMenu(int deviceId) { }
default void cancelPreloadRecentApps() { }
- default void setWindowState(int window, int state) { }
+
+ /**
+ * Called to notify window state changes.
+ * @see IStatusBar#setWindowState(int, int, int)
+ *
+ * @param displayId The id of the display to notify.
+ * @param window Window type. It should be one of {@link StatusBarManager#WINDOW_STATUS_BAR}
+ * or {@link StatusBarManager#WINDOW_NAVIGATION_BAR}
+ * @param state Window visible state.
+ */
+ default void setWindowState(int displayId, @WindowType int window,
+ @WindowVisibleState int state) { }
default void showScreenPinningRequest(int taskId) { }
- default void appTransitionPending(boolean forced) { }
- default void appTransitionCancelled() { }
- default void appTransitionStarting(long startTime, long duration, boolean forced) { }
- default void appTransitionFinished() { }
+
+ /**
+ * Called to notify System UI that an application transition is pending.
+ * @see IStatusBar#appTransitionPending(int).
+ *
+ * @param displayId The id of the display to notify.
+ * @param forced {@code true} to force transition pending.
+ */
+ default void appTransitionPending(int displayId, boolean forced) { }
+
+ /**
+ * Called to notify System UI that an application transition is canceled.
+ * @see IStatusBar#appTransitionCancelled(int).
+ *
+ * @param displayId The id of the display to notify.
+ */
+ default void appTransitionCancelled(int displayId) { }
+
+ /**
+ * Called to notify System UI that an application transition is starting.
+ * @see IStatusBar#appTransitionStarting(int, long, long).
+ *
+ * @param displayId The id of the display to notify.
+ * @param startTime Transition start time.
+ * @param duration Transition duration.
+ * @param forced {@code true} to force transition pending.
+ */
+ default void appTransitionStarting(
+ int displayId, long startTime, long duration, boolean forced) { }
+
+ /**
+ * Called to notify System UI that an application transition is finished.
+ * @see IStatusBar#appTransitionFinished(int)
+ *
+ * @param displayId The id of the display to notify.
+ */
+ default void appTransitionFinished(int displayId) { }
default void showAssistDisclosure() { }
default void startAssist(Bundle args) { }
default void onCameraLaunchGestureDetected(int source) { }
@@ -176,18 +279,43 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
@VisibleForTesting
- public CommandQueue() {
+ public CommandQueue(Context context) {
+ context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
+ // We always have default display.
+ setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE);
}
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ mDisplayDisabled.remove(displayId);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) { }
+
+ // TODO(b/118592525): add multi-display support if needed.
public boolean panelsEnabled() {
- return (mDisable1 & StatusBarManager.DISABLE_EXPAND) == 0
- && (mDisable2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
+ final int disabled1 = getDisabled1(DEFAULT_DISPLAY);
+ final int disabled2 = getDisabled2(DEFAULT_DISPLAY);
+ return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0
+ && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
&& !ONLY_CORE_APPS;
}
public void addCallback(Callbacks callbacks) {
mCallbacks.add(callbacks);
- callbacks.disable(mDisable1, mDisable2, false /* animate */);
+ // TODO(b/117478341): find a better way to pass disable flags by display.
+ for (int i = 0; i < mDisplayDisabled.size(); i++) {
+ int displayId = mDisplayDisabled.keyAt(i);
+ int disabled1 = getDisabled1(displayId);
+ int disabled2 = getDisabled2(displayId);
+ callbacks.disable(displayId, disabled1, disabled2, false /* animate */);
+ }
}
public void removeCallback(Callbacks callbacks) {
@@ -209,12 +337,21 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
- public void disable(int state1, int state2, boolean animate) {
+ /**
+ * Called to notify that disable flags are updated.
+ * @see Callbacks#disable(int, int, int, boolean).
+ */
+ public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
+ boolean animate) {
synchronized (mLock) {
- mDisable1 = state1;
- mDisable2 = state2;
+ setDisabled(displayId, state1, state2);
mHandler.removeMessages(MSG_DISABLE);
- Message msg = mHandler.obtainMessage(MSG_DISABLE, state1, state2, animate);
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = displayId;
+ args.argi2 = state1;
+ args.argi3 = state2;
+ args.argi4 = animate ? 1 : 0;
+ Message msg = mHandler.obtainMessage(MSG_DISABLE, args);
if (Looper.myLooper() == mHandler.getLooper()) {
// If its the right looper execute immediately so hides can be handled quickly.
mHandler.handleMessage(msg);
@@ -225,14 +362,42 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
- public void disable(int displayId, int state1, int state2) {
- disable(state1, state2, true);
+ public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2) {
+ disable(displayId, state1, state2, true);
+ }
+
+ /**
+ * Apply current disable flags by {@link CommandQueue#disable(int, int, int, boolean)}.
+ *
+ * @param displayId The id of the display to notify.
+ * @param animate {@code true} to show animations.
+ */
+ public void recomputeDisableFlags(int displayId, boolean animate) {
+ int disabled1 = getDisabled1(displayId);
+ int disabled2 = getDisabled2(displayId);
+ disable(displayId, disabled1, disabled2, animate);
+ }
+
+ private void setDisabled(int displayId, int disabled1, int disabled2) {
+ mDisplayDisabled.put(displayId, new Pair<>(disabled1, disabled2));
}
- public void recomputeDisableFlags(boolean animate) {
- disable(mDisable1, mDisable2, animate);
+ private int getDisabled1(int displayId) {
+ return getDisabled(displayId).first;
+ }
+
+ private int getDisabled2(int displayId) {
+ return getDisabled(displayId).second;
+ }
+
+ private Pair<Integer, Integer> getDisabled(int displayId) {
+ Pair<Integer, Integer> disablePair = mDisplayDisabled.get(displayId);
+ if (disablePair == null) {
+ disablePair = new Pair<>(DISABLE_NONE, DISABLE2_NONE);
+ mDisplayDisabled.put(displayId, disablePair);
+ }
+ return disablePair;
}
public void animateExpandNotificationsPanel() {
@@ -270,7 +435,6 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
@@ -278,34 +442,38 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
// Don't coalesce these, since it might have one time flags set such as
// STATUS_BAR_UNHIDE which might get lost.
SomeArgs args = SomeArgs.obtain();
- args.argi1 = vis;
- args.argi2 = fullscreenStackVis;
- args.argi3 = dockedStackVis;
- args.argi4 = mask;
+ args.argi1 = displayId;
+ args.argi2 = vis;
+ args.argi3 = fullscreenStackVis;
+ args.argi4 = dockedStackVis;
+ args.argi5 = mask;
args.arg1 = fullscreenStackBounds;
args.arg2 = dockedStackBounds;
mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void topAppWindowChanged(int displayId, boolean menuVisible) {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
- mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
- null).sendToTarget();
+ mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED,
+ displayId, menuVisible ? 1 : 0, null).sendToTarget();
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
- Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
- m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = displayId;
+ args.argi2 = vis;
+ args.argi3 = backDisposition;
+ args.argi4 = showImeSwitcher ? 1 : 0;
+ args.arg1 = token;
+ Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args);
m.sendToTarget();
}
}
@@ -381,12 +549,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void setWindowState(int displayId, int window, int state) {
synchronized (mLock) {
// don't coalesce these
- mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
+ mHandler.obtainMessage(MSG_SET_WINDOW_STATE, displayId, window, state).sendToTarget();
}
}
@@ -397,44 +564,54 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void appTransitionPending(int displayId) {
- appTransitionPending(false /* forced */);
+ appTransitionPending(displayId, false /* forced */);
}
- public void appTransitionPending(boolean forced) {
+ /**
+ * Called to notify System UI that an application transition is pending.
+ * @see Callbacks#appTransitionPending(int, boolean)
+ */
+ public void appTransitionPending(int displayId, boolean forced) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, displayId, forced ? 1 : 0)
+ .sendToTarget();
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void appTransitionCancelled(int displayId) {
synchronized (mLock) {
- mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
+ mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void appTransitionStarting(int displayId, long startTime, long duration) {
- appTransitionStarting(startTime, duration, false /* forced */);
+ appTransitionStarting(displayId, startTime, duration, false /* forced */);
}
- public void appTransitionStarting(long startTime, long duration, boolean forced) {
+ /**
+ * Called to notify System UI that an application transition is starting.
+ * @see Callbacks#appTransitionStarting(int, long, long, boolean).
+ */
+ public void appTransitionStarting(int displayId, long startTime, long duration,
+ boolean forced) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
- Pair.create(startTime, duration)).sendToTarget();
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = displayId;
+ args.argi2 = forced ? 1 : 0;
+ args.arg1 = startTime;
+ args.arg2 = duration;
+ mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, args).sendToTarget();
}
}
- // TODO(b/117478341): Add multi-display support.
@Override
public void appTransitionFinished(int displayId) {
synchronized (mLock) {
- mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
+ mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
}
}
@@ -619,8 +796,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
break;
}
case MSG_DISABLE:
+ SomeArgs args = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).disable(msg.arg1, msg.arg2, (Boolean) msg.obj);
+ mCallbacks.get(i).disable(args.argi1, args.argi2, args.argi3,
+ args.argi4 != 0 /* animate */);
}
break;
case MSG_EXPAND_NOTIFICATIONS:
@@ -644,22 +823,23 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
- SomeArgs args = (SomeArgs) msg.obj;
+ args = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
- args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+ args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2);
}
args.recycle();
break;
case MSG_TOP_APP_WINDOW_CHANGED:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).topAppWindowChanged(msg.arg1 != 0);
+ mCallbacks.get(i).topAppWindowChanged(msg.arg1, msg.arg2 != 0);
}
break;
case MSG_SHOW_IME_BUTTON:
+ args = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
- msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+ mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1,
+ args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */);
}
break;
case MSG_SHOW_RECENT_APPS:
@@ -699,7 +879,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
break;
case MSG_SET_WINDOW_STATE:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2);
+ mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2, (int) msg.obj);
}
break;
case MSG_SHOW_SCREEN_PIN_REQUEST:
@@ -709,24 +889,24 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
break;
case MSG_APP_TRANSITION_PENDING:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).appTransitionPending(msg.arg1 != 0);
+ mCallbacks.get(i).appTransitionPending(msg.arg1, msg.arg2 != 0);
}
break;
case MSG_APP_TRANSITION_CANCELLED:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).appTransitionCancelled();
+ mCallbacks.get(i).appTransitionCancelled(msg.arg1);
}
break;
case MSG_APP_TRANSITION_STARTING:
+ args = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
- Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
- mCallbacks.get(i).appTransitionStarting(data.first, data.second,
- msg.arg1 != 0);
+ mCallbacks.get(i).appTransitionStarting(args.argi1, (long) args.arg1,
+ (long) args.arg2, args.argi2 != 0 /* forced */);
}
break;
case MSG_APP_TRANSITION_FINISHED:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).appTransitionFinished();
+ mCallbacks.get(i).appTransitionFinished(msg.arg1);
}
break;
case MSG_ASSIST_DISCLOSURE:
@@ -858,7 +1038,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
public static class CommandQueueStart extends SystemUI {
@Override
public void start() {
- putComponent(CommandQueue.class, new CommandQueue());
+ putComponent(CommandQueue.class, new CommandQueue(mContext));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java
deleted file mode 100644
index 78172f19d291..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DisplayNavigationBarController.java
+++ /dev/null
@@ -1,148 +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.
- */
-
-package com.android.systemui.statusbar;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
-
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.View;
-import android.view.WindowManagerGlobal;
-
-import com.android.systemui.statusbar.phone.NavigationBarFragment;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-/**
- * A controller to handle external navigation bars
- */
-@Singleton
-public class DisplayNavigationBarController implements DisplayListener {
-
- private static final String TAG = DisplayNavigationBarController.class.getName();
-
- private final Context mContext;
- private final Handler mHandler;
- private final DisplayManager mDisplayManager;
-
- /** A displayId - nav bar mapping */
- private SparseArray<NavigationBarFragment> mExternalNavigationBarMap = new SparseArray<>();
-
- @Inject
- public DisplayNavigationBarController(Context context,
- @Named(MAIN_HANDLER_NAME) Handler handler) {
- mContext = context;
- mHandler = handler;
- mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-
- registerListener();
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- final Display display = mDisplayManager.getDisplay(displayId);
- addExternalNavigationBar(display);
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- final NavigationBarFragment navBar = mExternalNavigationBarMap.get(displayId);
- if (navBar != null) {
- final View navigationView = navBar.getView().getRootView();
- WindowManagerGlobal.getInstance().removeView(navigationView, true);
- mExternalNavigationBarMap.remove(displayId);
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- }
-
- /** Create external navigation bars when car/status bar initializes */
- public void createNavigationBars() {
- // Add external navigation bars if more than one displays exist.
- final Display[] displays = mDisplayManager.getDisplays();
- for (Display display : displays) {
- addExternalNavigationBar(display);
- }
- }
-
- /** remove external navigation bars and unset everything related to external navigation bars */
- public void destroy() {
- unregisterListener();
- if (mExternalNavigationBarMap.size() > 0) {
- for (int i = 0; i < mExternalNavigationBarMap.size(); i++) {
- final View navigationWindow = mExternalNavigationBarMap.valueAt(i)
- .getView().getRootView();
- WindowManagerGlobal.getInstance()
- .removeView(navigationWindow, true /* immediate */);
- }
- mExternalNavigationBarMap.clear();
- }
- }
-
- private void registerListener() {
- mDisplayManager.registerDisplayListener(this, mHandler);
- }
-
- private void unregisterListener() {
- mDisplayManager.unregisterDisplayListener(this);
- }
-
- /**
- * Add a phone navigation bar on an external display if the display supports system decorations.
- *
- * @param display the display to add navigation bar on
- */
- private void addExternalNavigationBar(Display display) {
- if (display == null || display.getDisplayId() == DEFAULT_DISPLAY
- || !display.supportsSystemDecorations()) {
- return;
- }
-
- final int displayId = display.getDisplayId();
- final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
-
- try {
- if (!wms.hasNavigationBar(displayId)) {
- return;
- }
- } catch (RemoteException e) {
- // Cannot get wms, just return with warning message.
- Log.w(TAG, "Cannot get WindowManager.");
- return;
- }
- final Context externalDisplayContext = mContext.createDisplayContext(display);
- NavigationBarFragment.create(externalDisplayContext, (tag, fragment) -> {
- final NavigationBarFragment navBar = (NavigationBarFragment) fragment;
- // TODO(b/115978725): handle external nav bars sysuiVisibility
- navBar.setCurrentSysuiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
- mExternalNavigationBarMap.append(displayId, navBar);
- });
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index b39a96d40828..e2177774a75d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -31,8 +31,8 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
new file mode 100644
index 000000000000..9740d1dd6d1c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+
+/** A controller to handle navigation bars. */
+@Singleton
+public class NavigationBarController implements DisplayListener {
+
+ private static final String TAG = NavigationBarController.class.getName();
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final DisplayManager mDisplayManager;
+
+ /** A displayId - nav bar maps. */
+ private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+
+ @Inject
+ public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+ mDisplayManager.registerDisplayListener(this, mHandler);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ Display display = mDisplayManager.getDisplay(displayId);
+ createNavigationBar(display);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ removeNavigationBar(displayId);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ }
+
+ // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
+ // CarStatusBar because they have their own nav bar. Think about a better way for it.
+ /**
+ * Creates navigation bars when car/status bar initializes.
+ *
+ * @param includeDefaultDisplay {@code true} to create navigation bar on default display.
+ */
+ public void createNavigationBars(final boolean includeDefaultDisplay) {
+ Display[] displays = mDisplayManager.getDisplays();
+ for (Display display : displays) {
+ if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
+ createNavigationBar(display);
+ }
+ }
+ }
+
+ /**
+ * Adds a navigation bar on default display or an external display if the display supports
+ * system decorations.
+ *
+ * @param display the display to add navigation bar on.
+ */
+ private void createNavigationBar(Display display) {
+ if (display == null
+ || (display.getDisplayId() != DEFAULT_DISPLAY
+ && !display.supportsSystemDecorations())) {
+ return;
+ }
+
+ final int displayId = display.getDisplayId();
+ final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
+ final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
+
+ try {
+ if (!wms.hasNavigationBar(displayId)) {
+ return;
+ }
+ } catch (RemoteException e) {
+ // Cannot get wms, just return with warning message.
+ Log.w(TAG, "Cannot get WindowManager.");
+ return;
+ }
+ final Context context = isOnDefaultDisplay
+ ? mContext
+ : mContext.createDisplayContext(display);
+ NavigationBarFragment.create(context, (tag, fragment) -> {
+ NavigationBarFragment navBar = (NavigationBarFragment) fragment;
+
+ // Unfortunately, we still need it because status bar needs LightBarController
+ // before notifications creation. We cannot directly use getLightBarController()
+ // from NavigationBarFragment directly.
+ LightBarController lightBarController = isOnDefaultDisplay
+ ? Dependency.get(LightBarController.class)
+ : new LightBarController(context,
+ Dependency.get(DarkIconDispatcher.class),
+ Dependency.get(BatteryController.class));
+ navBar.setLightBarController(lightBarController);
+
+ // TODO(b/118592525): to support multi-display, we start to add something which is
+ // per-display, while others may be global. I think it's time to add
+ // a new class maybe named DisplayDependency to solve per-display
+ // Dependency problem.
+ AutoHideController autoHideController = isOnDefaultDisplay
+ ? Dependency.get(AutoHideController.class)
+ : new AutoHideController(context, mHandler);
+ navBar.setAutoHideController(autoHideController);
+ navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ mNavigationBars.append(displayId, navBar);
+ });
+ }
+
+ /** Removes navigation bars. */
+ public void destroy() {
+ mDisplayManager.unregisterDisplayListener(this);
+ if (mNavigationBars.size() > 0) {
+ for (int i = 0; i < mNavigationBars.size(); i++) {
+ int displayId = mNavigationBars.keyAt(i);
+ removeNavigationBar(displayId);
+ }
+ mNavigationBars.clear();
+ }
+ }
+
+ private void removeNavigationBar(int displayId) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ View navigationWindow = navBar.getView().getRootView();
+ WindowManagerGlobal.getInstance()
+ .removeView(navigationWindow, true /* immediate */);
+ mNavigationBars.remove(displayId);
+ }
+ }
+
+ /** @see NavigationBarFragment#checkNavBarModes() */
+ public void checkNavBarModes(int displayId) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ navBar.checkNavBarModes();
+ }
+ }
+
+ /** @see NavigationBarFragment#finishBarAnimations() */
+ public void finishBarAnimations(int displayId) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ navBar.finishBarAnimations();
+ }
+ }
+
+ /** @see NavigationBarFragment#touchAutoDim() */
+ public void touchAutoDim(int displayId) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ navBar.touchAutoDim();
+ }
+ }
+
+ /** @see NavigationBarFragment#transitionTo(int, boolean) */
+ public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ navBar.transitionTo(barMode, animate);
+ }
+ }
+
+ /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
+ public void disableAnimationsDuringHide(int displayId, long delay) {
+ NavigationBarFragment navBar = mNavigationBars.get(displayId);
+ if (navBar != null) {
+ navBar.disableAnimationsDuringHide(delay);
+ }
+ }
+
+ /** @return {@link NavigationBarView} on the default display. */
+ public NavigationBarView getDefaultNavigationBarView() {
+ NavigationBarFragment navBar = mNavigationBars.get(DEFAULT_DISPLAY);
+ return (navBar == null) ? null : (NavigationBarView) navBar.getView();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e4c6981a84fa..e59bc2a82c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -37,11 +37,11 @@ import android.media.session.PlaybackState;
import android.os.Handler;
import android.os.Trace;
import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
@@ -157,13 +157,9 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onEntryRemoved(
Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ NotificationVisibility visibility,
boolean removedByUser) {
- if (!lifetimeExtended) {
- onNotificationRemoved(key);
- }
+ onNotificationRemoved(entry.key);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 2e9f6d072305..1ab9c5c2b4a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT
import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
@@ -252,13 +253,11 @@ public class NotificationRemoteInputManager implements Dumpable {
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onEntryRemoved(
- NotificationData.Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ @Nullable NotificationData.Entry entry,
+ NotificationVisibility visibility,
boolean removedByUser) {
- if (removedByUser) {
- onPerformRemoveNotification(entry, key);
+ if (removedByUser && entry != null) {
+ onPerformRemoveNotification(entry, entry.key);
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index f1a891b95eaa..d1b3c3cb12d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -30,8 +30,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index e7b768f30023..6d2c001dc153 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -41,9 +41,9 @@ import android.widget.LinearLayout;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.IconLogger;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 8b61a5bccc3c..3c1335456d04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index bc89889c48fe..4db981d2dcd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -37,8 +37,8 @@ import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
StatusIconDisplayable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 045221f510fa..c5751c300c01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -37,8 +37,8 @@ import android.widget.LinearLayout;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
/**
* Start small: StatusBarWifiView will be able to layout from a WifiIconState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
index beb90b893ec8..d541fae4ed33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
public interface StatusIconDisplayable extends DarkReceiver {
String getSlot();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 099b503b1131..2bb0d5ce9161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -24,6 +24,7 @@ import android.app.Notification;
import android.service.notification.StatusBarNotification;
import android.util.Log;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationListener;
@@ -82,11 +83,9 @@ public class NotificationAlertingManager {
@Override
public void onEntryRemoved(
NotificationData.Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ NotificationVisibility visibility,
boolean removedByUser) {
- stopAlerting(key);
+ stopAlerting(entry.key);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 27c283749abc..a51896ee69fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -90,7 +90,7 @@ public class NotificationData {
private static final long INITIALIZATION_DELAY = 400;
private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
private static final int COLOR_INVALID = 1;
- public String key;
+ public final String key;
public StatusBarNotification notification;
public NotificationChannel channel;
public long lastAudiblyAlertedMs;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 8351c4062ab9..2f60f115ed53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -15,8 +15,10 @@
*/
package com.android.systemui.statusbar.notification;
+import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
/**
@@ -59,20 +61,24 @@ public interface NotificationEntryListener {
}
/**
+ * Called when an error occurred inflating the views for a notification.
+ */
+ default void onInflationError(StatusBarNotification notification, Exception exception) {
+ }
+
+ /**
* Called when a notification has been removed (either because the user swiped it away or
* because the developer retracted it).
* @param entry notification data entry that was removed. Null if no entry existed for the
* removed key at the time of removal.
- * @param key key of notification that was removed
- * @param old StatusBarNotification of the notification before it was removed
- * @param lifetimeExtended true if something is artificially extending how long the notification
+ * @param visibility logging data related to the visibility of the notification at the time of
+ * removal, if it was removed by a user action. Null if it was not removed by
+ * a user action.
* @param removedByUser true if the notification was removed by a user action
*/
default void onEntryRemoved(
NotificationData.Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ @Nullable NotificationVisibility visibility,
boolean removedByUser) {
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 39236fad1def..5d6f60eadf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,38 +15,28 @@
*/
package com.android.systemui.statusbar.notification;
-import static com.android.systemui.bubbles.BubbleController.DEBUG_DEMOTE_TO_NOTIF;
-
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.os.Handler;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
@@ -71,8 +61,7 @@ public class NotificationEntryManager implements
Dumpable,
NotificationInflater.InflationCallback,
NotificationUpdateHandler,
- VisualStabilityManager.Callback,
- BubbleController.BubbleDismissListener {
+ VisualStabilityManager.Callback {
private static final String TAG = "NotificationEntryMgr";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -87,9 +76,6 @@ public class NotificationEntryManager implements
Dependency.get(DeviceProvisionedController.class);
private final ForegroundServiceController mForegroundServiceController =
Dependency.get(ForegroundServiceController.class);
- private final AmbientPulseManager mAmbientPulseManager =
- Dependency.get(AmbientPulseManager.class);
- private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
// Lazily retrieved dependencies
private NotificationRemoteInputManager mRemoteInputManager;
@@ -98,11 +84,8 @@ public class NotificationEntryManager implements
private final Handler mDeferredNotificationViewUpdateHandler;
private Runnable mUpdateNotificationViewsCallback;
- protected IStatusBarService mBarService;
private NotificationPresenter mPresenter;
- protected PowerManager mPowerManager;
private NotificationListenerService.RankingMap mLatestRankingMap;
- protected HeadsUpManager mHeadsUpManager;
protected NotificationData mNotificationData;
protected NotificationListContainer mListContainer;
@VisibleForTesting
@@ -138,10 +121,6 @@ public class NotificationEntryManager implements
public NotificationEntryManager(Context context) {
mContext = context;
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mBubbleController.setDismissListener(this /* bubbleEventListener */);
mNotificationData = new NotificationData();
mDeferredNotificationViewUpdateHandler = new Handler();
}
@@ -168,25 +147,34 @@ public class NotificationEntryManager implements
return mNotificationRowBinder;
}
+ // TODO: Remove this once we can always use a mocked row binder in our tests
+ @VisibleForTesting
+ void setRowBinder(NotificationRowBinder notificationRowBinder) {
+ mNotificationRowBinder = notificationRowBinder;
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer,
HeadsUpManager headsUpManager) {
mPresenter = presenter;
mUpdateNotificationViewsCallback = mPresenter::updateNotificationViews;
- mHeadsUpManager = headsUpManager;
- mNotificationData.setHeadsUpManager(mHeadsUpManager);
+ mNotificationData.setHeadsUpManager(headsUpManager);
mListContainer = listContainer;
- mNotificationLifetimeExtenders.add(mHeadsUpManager);
- mNotificationLifetimeExtenders.add(mAmbientPulseManager);
- mNotificationLifetimeExtenders.add(mGutsManager);
- mNotificationLifetimeExtenders.addAll(getRemoteInputManager().getLifetimeExtenders());
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ }
- for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
- extender.setCallback(key -> removeNotification(key, mLatestRankingMap));
+ /** Adds multiple {@link NotificationLifetimeExtender}s. */
+ public void addNotificationLifetimeExtenders(List<NotificationLifetimeExtender> extenders) {
+ for (NotificationLifetimeExtender extender : extenders) {
+ addNotificationLifetimeExtender(extender);
}
+ }
- mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ /** Adds a {@link NotificationLifetimeExtender}. */
+ public void addNotificationLifetimeExtender(NotificationLifetimeExtender extender) {
+ mNotificationLifetimeExtenders.add(extender);
+ extender.setCallback(key -> removeNotification(key, mLatestRankingMap));
}
public NotificationData getNotificationData() {
@@ -201,10 +189,6 @@ public class NotificationEntryManager implements
return mPresenter;
}
- public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
- return getRowBinder().getNotificationLongClicker();
- }
-
@Override
public void onReorderingAllowed() {
updateNotifications();
@@ -215,43 +199,8 @@ public class NotificationEntryManager implements
final int count = mNotificationData.getActiveNotifications().size();
final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
true);
-
- final String pkg = n.getPackageName();
- final String tag = n.getTag();
- final int id = n.getId();
- final int userId = n.getUserId();
- try {
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (mHeadsUpManager.isAlerting(n.getKey())) {
- dismissalSurface = NotificationStats.DISMISSAL_PEEK;
- } else if (mListContainer.hasPulsingNotifications()) {
- dismissalSurface = NotificationStats.DISMISSAL_AOD;
- }
- int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
- mBarService.onNotificationClear(pkg, tag, id, userId, n.getKey(), dismissalSurface,
- dismissalSentiment, nv);
- removeNotificationInternal(
- n.getKey(), null, false /* forceRemove */, true /* removedByUser */);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
- }
-
- @Override
- public void onStackDismissed() {
- updateNotifications();
- }
-
- @Override
- public void onBubbleDismissed(String key) {
- NotificationData.Entry entry = mNotificationData.get(key);
- if (entry != null) {
- entry.setBubbleDismissed(true);
- if (!DEBUG_DEMOTE_TO_NOTIF) {
- performRemoveNotification(entry.notification);
- }
- }
- updateNotifications();
+ removeNotificationInternal(
+ n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */);
}
private void abortExistingInflation(String key) {
@@ -275,28 +224,10 @@ public class NotificationEntryManager implements
@Override
public void handleInflationException(StatusBarNotification n, Exception e) {
removeNotificationInternal(
- n.getKey(), null, true /* forceRemove */, false /* removedByUser */);
- try {
- mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
- n.getInitialPid(), e.getMessage(), n.getUserId());
- } catch (RemoteException ex) {
- // The end is nigh.
- }
- }
-
- private void addEntry(NotificationData.Entry shadeEntry) {
- if (shadeEntry == null) {
- return;
- }
- // Add the expanded view and icon.
- mNotificationData.add(shadeEntry);
- tagForeground(shadeEntry.notification);
- updateNotifications();
+ n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
- listener.onNotificationAdded(shadeEntry);
+ listener.onInflationError(n, e);
}
-
- maybeScheduleUpdateNotificationViews(shadeEntry);
}
private void maybeScheduleUpdateNotificationViews(NotificationData.Entry entry) {
@@ -320,7 +251,13 @@ public class NotificationEntryManager implements
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryInflated(entry, inflatedFlags);
}
- addEntry(entry);
+ mNotificationData.add(entry);
+ tagForeground(entry.notification);
+ updateNotifications();
+ for (NotificationEntryListener listener : mNotificationEntryListeners) {
+ listener.onNotificationAdded(entry);
+ }
+ maybeScheduleUpdateNotificationViews(entry);
} else {
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryReinflated(entry);
@@ -333,19 +270,19 @@ public class NotificationEntryManager implements
@Override
public void removeNotification(String key, NotificationListenerService.RankingMap ranking) {
removeNotificationInternal(
- key, ranking, false /* forceRemove */, false /* removedByUser */);
+ key, ranking, null, false /* forceRemove */, false /* removedByUser */);
}
private void removeNotificationInternal(
String key,
@Nullable NotificationListenerService.RankingMap ranking,
+ @Nullable NotificationVisibility visibility,
boolean forceRemove,
boolean removedByUser) {
final NotificationData.Entry entry = mNotificationData.get(key);
abortExistingInflation(key);
- StatusBarNotification old = null;
boolean lifetimeExtended = false;
if (entry != null) {
@@ -370,8 +307,6 @@ public class NotificationEntryManager implements
extender.setShouldManageLifetime(entry, false /* shouldManage */);
}
- mForegroundServiceController.removeNotification(entry.notification);
-
if (entry.rowExists()) {
entry.removeRow();
mListContainer.cleanUpViewStateForEntry(entry);
@@ -380,25 +315,15 @@ public class NotificationEntryManager implements
// Let's remove the children if this was a summary
handleGroupSummaryRemoved(key);
- old = removeNotificationViews(key, ranking);
- }
- }
-
- for (NotificationEntryListener listener : mNotificationEntryListeners) {
- listener.onEntryRemoved(entry, key, old, lifetimeExtended, removedByUser);
- }
- }
+ mNotificationData.remove(key, ranking);
+ updateNotifications();
+ Dependency.get(LeakDetector.class).trackGarbage(entry);
- private StatusBarNotification removeNotificationViews(String key,
- NotificationListenerService.RankingMap ranking) {
- NotificationData.Entry entry = mNotificationData.remove(key, ranking);
- if (entry == null) {
- Log.w(TAG, "removeNotification for unknown key: " + key);
- return null;
+ for (NotificationEntryListener listener : mNotificationEntryListeners) {
+ listener.onEntryRemoved(entry, visibility, removedByUser);
+ }
+ }
}
- updateNotifications();
- Dependency.get(LeakDetector.class).trackGarbage(entry);
- return entry.notification;
}
/**
@@ -456,26 +381,6 @@ public class NotificationEntryManager implements
}
}
- private NotificationData.Entry createNotificationEntry(
- StatusBarNotification sbn, NotificationListenerService.Ranking ranking)
- throws InflationException {
- if (DEBUG) {
- Log.d(TAG, "createNotificationEntry(notification=" + sbn + " " + ranking);
- }
-
- NotificationData.Entry entry = new NotificationData.Entry(sbn, ranking);
- if (BubbleController.shouldAutoBubble(getContext(), entry)) {
- entry.setIsBubble(true);
- }
-
- Dependency.get(LeakDetector.class).trackInstance(entry);
- entry.createIcons(mContext, sbn);
- // Construct the expanded view.
- getRowBinder().inflateViews(entry, () -> performRemoveNotification(sbn),
- mNotificationData.get(entry.key) != null);
- return entry;
- }
-
private void addNotificationInternal(StatusBarNotification notification,
NotificationListenerService.RankingMap rankingMap) throws InflationException {
String key = notification.getKey();
@@ -486,11 +391,15 @@ public class NotificationEntryManager implements
mNotificationData.updateRanking(rankingMap);
NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
rankingMap.getRanking(key, ranking);
- NotificationData.Entry entry = createNotificationEntry(notification, ranking);
- abortExistingInflation(key);
- mForegroundServiceController.addNotification(notification,
- mNotificationData.getImportance(key));
+ NotificationData.Entry entry = new NotificationData.Entry(notification, ranking);
+
+ Dependency.get(LeakDetector.class).trackInstance(entry);
+ // Construct the expanded view.
+ getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
+ mNotificationData.get(entry.key) != null);
+
+ abortExistingInflation(key);
mPendingNotifications.put(key, entry);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
@@ -549,13 +458,9 @@ public class NotificationEntryManager implements
mNotificationData.update(entry, ranking, notification);
- entry.updateIcons(mContext, notification);
getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
mNotificationData.get(entry.key) != null);
- mForegroundServiceController.updateNotification(notification,
- mNotificationData.getImportance(key));
-
updateNotifications();
if (!notification.isClearable()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 5e99c388655f..700382a103b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -117,8 +117,8 @@ public class NotificationFilter {
return true;
}
- if (getFsc().isDungeonNotification(sbn)
- && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
+ if (getFsc().isDisclosureNotification(sbn)
+ && !getFsc().isDisclosureNeededForUser(sbn.getUserId())) {
// this is a foreground-service disclosure for a user that does not need to show one
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index b241b8a70b3f..058efca51b21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -51,6 +52,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import javax.inject.Inject;
+import javax.inject.Named;
import javax.inject.Singleton;
/** Handles inflating and updating views for notifications. */
@@ -72,6 +74,7 @@ public class NotificationRowBinder {
private final NotificationMessagingUtil mMessagingUtil;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
+ private final boolean mAllowLongPress;
private NotificationRemoteInputManager mRemoteInputManager;
private NotificationPresenter mPresenter;
@@ -83,9 +86,11 @@ public class NotificationRowBinder {
private NotificationClicker mNotificationClicker;
@Inject
- public NotificationRowBinder(Context context) {
+ public NotificationRowBinder(Context context,
+ @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress) {
mContext = context;
mMessagingUtil = new NotificationMessagingUtil(context);
+ mAllowLongPress = allowLongPress;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
@@ -120,17 +125,22 @@ public class NotificationRowBinder {
/**
* Inflates the views for the given entry (possibly asynchronously).
*/
- public void inflateViews(NotificationData.Entry entry, Runnable onDismissRunnable,
- boolean isUpdate) {
+ public void inflateViews(
+ NotificationData.Entry entry,
+ Runnable onDismissRunnable,
+ boolean isUpdate)
+ throws InflationException {
ViewGroup parent = mListContainer.getViewParentForNotification(entry);
PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
entry.notification.getUser().getIdentifier());
final StatusBarNotification sbn = entry.notification;
if (entry.rowExists()) {
+ entry.updateIcons(mContext, sbn);
entry.reset();
updateNotification(entry, pmUser, sbn, entry.getRow(), isUpdate);
} else {
+ entry.createIcons(mContext, sbn);
new RowInflaterTask().inflate(mContext, parent, entry,
row -> {
bindRow(entry, pmUser, sbn, row, onDismissRunnable);
@@ -147,7 +157,9 @@ public class NotificationRowBinder {
row.setHeadsUpManager(mHeadsUpManager);
row.setOnExpandClickListener(mPresenter);
row.setInflationCallback(mInflationCallback);
- row.setLongPressListener(getNotificationLongClicker());
+ if (mAllowLongPress) {
+ row.setLongPressListener(mGutsManager::openGuts);
+ }
mListContainer.bindRow(row);
getRemoteInputManager().bindRow(row);
@@ -260,10 +272,6 @@ public class NotificationRowBinder {
row.inflateViews();
}
- ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
- return mGutsManager::openGuts;
- }
-
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mUiOffloadThread.submit(() -> {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 75bad6d20a2f..43048a2c087e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -21,6 +21,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
@@ -32,8 +34,10 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
import java.util.Collection;
@@ -60,7 +64,8 @@ public class NotificationLogger implements StateListener {
// Dependencies:
private final NotificationListenerService mNotificationListener;
private final UiOffloadThread mUiOffloadThread;
- protected NotificationEntryManager mEntryManager;
+ private final NotificationEntryManager mEntryManager;
+ private HeadsUpManager mHeadsUpManager;
protected Handler mHandler = new Handler();
protected IStatusBarService mBarService;
@@ -158,12 +163,35 @@ public class NotificationLogger implements StateListener {
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
+
+ entryManager.addNotificationEntryListener(new NotificationEntryListener() {
+ @Override
+ public void onEntryRemoved(
+ NotificationData.Entry entry,
+ NotificationVisibility visibility,
+ boolean removedByUser) {
+ if (removedByUser && visibility != null) {
+ logNotificationClear(entry.key, entry.notification, visibility);
+ }
+ }
+
+ @Override
+ public void onInflationError(
+ StatusBarNotification notification,
+ Exception exception) {
+ logNotificationError(notification, exception);
+ }
+ });
}
public void setUpWithContainer(NotificationListContainer listContainer) {
mListContainer = listContainer;
}
+ public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+ mHeadsUpManager = headsUpManager;
+ }
+
public void stopNotificationLogging() {
// Report all notifications as invisible and turn down the
// reporter.
@@ -193,6 +221,45 @@ public class NotificationLogger implements StateListener {
}
}
+ private void logNotificationClear(String key, StatusBarNotification notification,
+ NotificationVisibility nv) {
+ final String pkg = notification.getPackageName();
+ final String tag = notification.getTag();
+ final int id = notification.getId();
+ final int userId = notification.getUserId();
+ try {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ if (mHeadsUpManager.isAlerting(key)) {
+ dismissalSurface = NotificationStats.DISMISSAL_PEEK;
+ } else if (mListContainer.hasPulsingNotifications()) {
+ dismissalSurface = NotificationStats.DISMISSAL_AOD;
+ }
+ int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+ mBarService.onNotificationClear(pkg, tag, id, userId, notification.getKey(),
+ dismissalSurface,
+ dismissalSentiment, nv);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ }
+
+ private void logNotificationError(
+ StatusBarNotification notification,
+ Exception exception) {
+ try {
+ mBarService.onNotificationError(
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUid(),
+ notification.getInitialPid(),
+ exception.getMessage(),
+ notification.getUserId());
+ } catch (RemoteException ex) {
+ // The end is nigh.
+ }
+ }
+
private void logNotificationVisibilityChanges(
Collection<NotificationVisibility> newlyVisible,
Collection<NotificationVisibility> noLongerVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 5329541db92a..b1eab8069307 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -40,6 +40,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.Handler;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
@@ -150,6 +151,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// Reset exit counter that we'll log and record an undo event separately (not an exit event)
mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
+ mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
swapContent(ACTION_UNDO, true /* animate */);
};
@@ -381,6 +383,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
+ /**
+ * Returns an initialized LogMaker for logging importance changes.
+ * The caller may override the type (to DISMISS) before passing it to mMetricsLogger.
+ * @return new LogMaker
+ */
+ private LogMaker importanceChangeLogMaker() {
+ return new LogMaker(MetricsEvent.ACTION_SAVE_IMPORTANCE)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(mChosenImportance - mStartingChannelImportance);
+ }
+
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null
&& mStartingChannelImportance != mChosenImportance;
@@ -397,8 +410,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
* Commits the updated importance values on the background thread.
*/
private void updateImportance() {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
- mChosenImportance - mStartingChannelImportance);
+ mMetricsLogger.write(importanceChangeLogMaker());
Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
bgHandler.post(new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
index 8c8bad2ab196..a5411ecb4bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -87,8 +87,8 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso
try {
drawable = mResolver.resolveImage(target);
- } catch (IOException ex) {
- Log.d(TAG, "PreloadImageTask: Resolve failed from " + target);
+ } catch (IOException | SecurityException ex) {
+ Log.d(TAG, "PreloadImageTask: Resolve failed from " + target, ex);
}
return drawable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 588246f3d2c6..a3e13053d169 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -81,8 +81,8 @@ public class NotificationInlineImageResolver implements ImageResolver {
Drawable result = null;
try {
result = hasCache() ? mImageCache.get(uri) : resolveImage(uri);
- } catch (IOException ex) {
- Log.d(TAG, "loadImage: Can't load image from " + uri);
+ } catch (IOException | SecurityException ex) {
+ Log.d(TAG, "loadImage: Can't load image from " + uri, ex);
}
return result;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f982ecf6f103..8deb7d5e8456 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -16,9 +16,11 @@
package com.android.systemui.statusbar.notification.stack;
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -136,6 +138,9 @@ import java.util.HashSet;
import java.util.List;
import java.util.function.BiConsumer;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
@@ -165,6 +170,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
private boolean mLowPriorityBeforeSpeedBump;
+ private final boolean mAllowLongPress;
private float mExpandedHeight;
private int mOwnScrollY;
@@ -452,27 +458,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private final NotificationGutsManager
mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public NotificationStackScrollLayout(Context context) {
- this(context, null);
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
+ @Inject
+ public NotificationStackScrollLayout(
+ @Named(VIEW_CONTEXT) Context context,
+ AttributeSet attrs,
+ @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress) {
+ super(context, attrs, 0, 0);
Resources res = getResources();
+ mAllowLongPress = allowLongPress;
+
for (int i = 0; i < NUM_SECTIONS; i++) {
mSections[i] = new NotificationSection(this);
}
@@ -532,7 +527,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
inflateEmptyShadeView();
inflateFooterView();
mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
- setLongPressListener(mEntryManager.getNotificationLongClicker());
+ if (mAllowLongPress) {
+ setLongPressListener(mGutsManager::openGuts);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index f1d9549b9284..975aee51228b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -189,10 +189,13 @@ class NotificationSwipeHelper extends SwipeHelper
boolean isFastNonDismissGesture =
gestureFastEnough && !gestureTowardsMenu && !isDismissGesture;
boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough || isFastNonDismissGesture;
- if (isNonDismissGestureTowardsMenu
- || (!isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu)) {
+ int menuSnapTarget = menuRow.getMenuSnapTarget();
+ boolean isNonFalseMenuRevealingGesture =
+ !isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu;
+ if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture)
+ && menuSnapTarget != 0) {
// Menu has not been snapped to previously and this is menu revealing gesture
- snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ snapOpen(animView, menuSnapTarget, velocity);
menuRow.onSnapOpen();
} else if (isDismissGesture(ev) && !gestureTowardsMenu) {
dismiss(animView, velocity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
new file mode 100644
index 000000000000..b9425d4745d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/** A controller to control all auto-hide things. */
+public class AutoHideController implements CommandQueue.Callbacks {
+ private static final String TAG = "AutoHideController";
+
+ private final IWindowManager mWindowManagerService;
+
+ private final Handler mHandler;
+ private final NotificationRemoteInputManager mRemoteInputManager;
+ private final CommandQueue mCommandQueue;
+ private StatusBar mStatusBar;
+ private NavigationBarFragment mNavigationBar;
+
+ private int mDisplayId;
+ private int mSystemUiVisibility;
+ // last value sent to window manager
+ private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
+
+ private boolean mAutoHideSuspended;
+
+ private static final long AUTOHIDE_TIMEOUT_MS = 2250;
+
+ private final Runnable mAutoHide = () -> {
+ int requested = mSystemUiVisibility & ~getTransientMask();
+ if (mSystemUiVisibility != requested) {
+ notifySystemUiVisibilityChanged(requested);
+ }
+ };
+
+ @Inject
+ public AutoHideController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+ mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+ mCommandQueue.addCallback(this);
+ mHandler = handler;
+ mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+ mWindowManagerService = Dependency.get(IWindowManager.class);
+
+ mDisplayId = context.getDisplayId();
+ }
+
+ void setStatusBar(StatusBar statusBar) {
+ mStatusBar = statusBar;
+ }
+
+ void setNavigationBar(NavigationBarFragment navigationBar) {
+ mNavigationBar = navigationBar;
+ }
+
+ @Override
+ public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ int oldVal = mSystemUiVisibility;
+ int newVal = (oldVal & ~mask) | (vis & mask);
+ int diff = newVal ^ oldVal;
+
+ if (diff != 0) {
+ mSystemUiVisibility = newVal;
+
+ // ready to unhide
+ if (hasStatusBar() && (vis & View.STATUS_BAR_UNHIDE) != 0) {
+ mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+ }
+
+ if (hasNavigationBar() && (vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+ mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+ }
+
+ // Re-send setSystemUiVisibility to update un-hide status.
+ if (mSystemUiVisibility != newVal) {
+ mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility,
+ fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds,
+ dockedStackBounds);
+ }
+
+ notifySystemUiVisibilityChanged(mSystemUiVisibility);
+ }
+ }
+
+ private void notifySystemUiVisibilityChanged(int vis) {
+ try {
+ if (mLastDispatchedSystemUiVisibility != vis) {
+ mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
+ mLastDispatchedSystemUiVisibility = vis;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Cannot get WindowManager");
+ }
+ }
+
+ void resumeSuspendedAutoHide() {
+ if (mAutoHideSuspended) {
+ scheduleAutoHide();
+ Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+ if (checkBarModesRunnable != null) {
+ mHandler.postDelayed(checkBarModesRunnable, 500); // longer than home -> launcher
+ }
+ }
+ }
+
+ void suspendAutoHide() {
+ mHandler.removeCallbacks(mAutoHide);
+ Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+ if (checkBarModesRunnable != null) {
+ mHandler.removeCallbacks(checkBarModesRunnable);
+ }
+ mAutoHideSuspended = (mSystemUiVisibility & getTransientMask()) != 0;
+ }
+
+ void touchAutoHide() {
+ // update transient bar auto hide
+ if ((hasStatusBar() && mStatusBar.getStatusBarMode() == MODE_SEMI_TRANSPARENT)
+ || hasNavigationBar() && mNavigationBar.isSemiTransparent()) {
+ scheduleAutoHide();
+ } else {
+ cancelAutoHide();
+ }
+ }
+
+ private Runnable getCheckBarModesRunnable() {
+ if (hasStatusBar()) {
+ return () -> mStatusBar.checkBarModes();
+ } else if (hasNavigationBar()) {
+ return () -> mNavigationBar.checkNavBarModes();
+ } else {
+ return null;
+ }
+ }
+
+ private void cancelAutoHide() {
+ mAutoHideSuspended = false;
+ mHandler.removeCallbacks(mAutoHide);
+ }
+
+ private void scheduleAutoHide() {
+ cancelAutoHide();
+ mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
+ }
+
+ void checkUserAutoHide(MotionEvent event) {
+ boolean shouldAutoHide =
+ (mSystemUiVisibility & getTransientMask()) != 0 // a transient bar is revealed.
+ && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
+ && event.getX() == 0 && event.getY() == 0;
+ if (hasStatusBar()) {
+ // a touch outside both bars
+ shouldAutoHide &= !mRemoteInputManager.getController().isRemoteInputActive();
+ }
+ if (shouldAutoHide) {
+ userAutoHide();
+ }
+ }
+
+ private void userAutoHide() {
+ cancelAutoHide();
+ mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
+ }
+
+ private int getTransientMask() {
+ int mask = 0;
+ if (hasStatusBar()) {
+ mask |= View.STATUS_BAR_TRANSIENT;
+ }
+ if (hasNavigationBar()) {
+ mask |= View.NAVIGATION_BAR_TRANSIENT;
+ }
+ return mask;
+ }
+
+ private boolean hasNavigationBar() {
+ return mNavigationBar != null;
+ }
+
+ private boolean hasStatusBar() {
+ return mStatusBar != null;
+ }
+}
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 1d7e899afc10..fac4dbbe735a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -30,6 +30,9 @@ import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Manages which tiles should be automatically added to QS.
*/
@@ -44,24 +47,31 @@ public class AutoTileManager {
private final QSTileHost mHost;
private final Handler mHandler;
private final AutoAddTracker mAutoTracker;
-
- public AutoTileManager(Context context, QSTileHost host) {
- this(context, new AutoAddTracker(context), host,
- new Handler(Dependency.get(Dependency.BG_LOOPER)));
- }
-
- @VisibleForTesting
- AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
- Handler handler) {
+ private final HotspotController mHotspotController;
+ private final DataSaverController mDataSaverController;
+ private final ManagedProfileController mManagedProfileController;
+ private final ColorDisplayController mColorDisplayController;
+
+ @Inject
+ public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
+ @Named(Dependency.BG_HANDLER_NAME) Handler handler,
+ HotspotController hotspotController,
+ DataSaverController dataSaverController,
+ ManagedProfileController managedProfileController,
+ ColorDisplayController colorDisplayController) {
mAutoTracker = autoAddTracker;
mContext = context;
mHost = host;
mHandler = handler;
+ mHotspotController = hotspotController;
+ mDataSaverController = dataSaverController;
+ mManagedProfileController = managedProfileController;
+ mColorDisplayController = colorDisplayController;
if (!mAutoTracker.isAdded(HOTSPOT)) {
- Dependency.get(HotspotController.class).addCallback(mHotspotCallback);
+ hotspotController.addCallback(mHotspotCallback);
}
if (!mAutoTracker.isAdded(SAVER)) {
- Dependency.get(DataSaverController.class).addCallback(mDataSaverListener);
+ dataSaverController.addCallback(mDataSaverListener);
}
if (!mAutoTracker.isAdded(INVERSION)) {
mColorsSetting = new SecureSetting(mContext, mHandler,
@@ -79,11 +89,11 @@ public class AutoTileManager {
mColorsSetting.setListening(true);
}
if (!mAutoTracker.isAdded(WORK)) {
- Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback);
+ managedProfileController.addCallback(mProfileCallback);
}
if (!mAutoTracker.isAdded(NIGHT)
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
- Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback);
+ colorDisplayController.setListener(mColorDisplayCallback);
}
}
@@ -92,11 +102,11 @@ public class AutoTileManager {
mColorsSetting.setListening(false);
}
mAutoTracker.destroy();
- Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
- Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
- Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
+ mHotspotController.removeCallback(mHotspotCallback);
+ mDataSaverController.removeCallback(mDataSaverListener);
+ mManagedProfileController.removeCallback(mProfileCallback);
if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
- Dependency.get(ColorDisplayController.class).setListener(null);
+ mColorDisplayController.setListener(null);
}
}
@@ -109,7 +119,7 @@ public class AutoTileManager {
@Override
public void onManagedProfileChanged() {
if (mAutoTracker.isAdded(WORK)) return;
- if (Dependency.get(ManagedProfileController.class).hasActiveProfile()) {
+ if (mManagedProfileController.hasActiveProfile()) {
mHost.addTile(WORK);
mAutoTracker.setTileAdded(WORK);
}
@@ -129,8 +139,7 @@ public class AutoTileManager {
if (isDataSaving) {
mHost.addTile(SAVER);
mAutoTracker.setTileAdded(SAVER);
- mHandler.post(() -> Dependency.get(DataSaverController.class).removeCallback(
- mDataSaverListener));
+ mHandler.post(() -> mDataSaverController.removeCallback(mDataSaverListener));
}
}
};
@@ -142,8 +151,7 @@ public class AutoTileManager {
if (enabled) {
mHost.addTile(HOTSPOT);
mAutoTracker.setTileAdded(HOTSPOT);
- mHandler.post(() -> Dependency.get(HotspotController.class)
- .removeCallback(mHotspotCallback));
+ mHandler.post(() -> mHotspotController.removeCallback(mHotspotCallback));
}
}
};
@@ -170,8 +178,7 @@ public class AutoTileManager {
if (mAutoTracker.isAdded(NIGHT)) return;
mHost.addTile(NIGHT);
mAutoTracker.setTileAdded(NIGHT);
- mHandler.post(() -> Dependency.get(ColorDisplayController.class)
- .setListener(null));
+ mHandler.post(() -> mColorDisplayController.setListener(null));
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 3d814732a2e7..79056175b595 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -36,6 +37,9 @@ import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class BarTransitions {
private static final boolean DEBUG = false;
private static final boolean DEBUG_COLORS = false;
@@ -48,6 +52,18 @@ public class BarTransitions {
public static final int MODE_WARNING = 5;
public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
+ @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ MODE_OPAQUE,
+ MODE_SEMI_TRANSPARENT,
+ MODE_TRANSLUCENT,
+ MODE_LIGHTS_OUT,
+ MODE_TRANSPARENT,
+ MODE_WARNING,
+ MODE_LIGHTS_OUT_TRANSPARENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransitionMode {}
+
public static final int LIGHTS_IN_DURATION = 250;
public static final int LIGHTS_OUT_DURATION = 1500;
public static final int BACKGROUND_DURATION = 200;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 24570aec9db4..f907b6523bef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -70,7 +70,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private SignalCallback mSignalCallback = new SignalCallback() {
@Override
public void setIsAirplaneMode(NetworkController.IconState icon) {
- mCommandQueue.recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
}
};
@@ -155,7 +155,10 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != getContext().getDisplayId()) {
+ return;
+ }
state1 = adjustDisableFlags(state1);
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
@@ -362,6 +365,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
@Override
public void onDozingChanged(boolean isDozing) {
- disable(mDisabled1, mDisabled1, false /* animate */);
+ disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index 5b44a77454b2..08a10dc925e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -14,7 +14,8 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.plugins.DarkIconDispatcher.DEFAULT_ICON_TINT;
+import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -24,7 +25,7 @@ import android.util.ArrayMap;
import android.widget.ImageView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -35,7 +36,7 @@ import javax.inject.Singleton;
/**
*/
@Singleton
-public class DarkIconDispatcherImpl implements DarkIconDispatcher {
+public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher {
private final LightBarTransitionsController mTransitionsController;
private final Rect mTintArea = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 3425dd237430..236c72c5cc2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -29,14 +29,14 @@ import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 3c8cad7cb60b..d1e488ab2b4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -25,12 +25,12 @@ import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import java.util.function.BiConsumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 5ba59b507fec..03375d20e6db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -45,13 +45,13 @@ import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 6632d5851119..b590ca7f4df0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -27,8 +27,8 @@ import android.view.View;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -44,7 +44,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
- private final DarkIconDispatcher mStatusBarIconController;
+ private final SysuiDarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
private BiometricUnlockController mBiometricUnlockController;
@@ -79,16 +79,13 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private final Rect mLastDockedBounds = new Rect();
private boolean mQsCustomizing;
- private final Context mContext;
-
@Inject
public LightBarController(Context ctx, DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController) {
mDarkModeColor = Color.valueOf(ctx.getColor(R.color.dark_mode_icon_color_single_tone));
- mStatusBarIconController = darkIconDispatcher;
+ mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
mBatteryController = batteryController;
mBatteryController.addCallback(this);
- mContext = ctx;
}
public void setNavigationBar(LightBarTransitionsController navigationBar) {
@@ -225,9 +222,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private void updateNavigation() {
if (mNavigationBarController != null) {
- if (!NavBarTintController.isEnabled(mContext)) {
- mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
- }
+ mNavigationBarController.setIconsDark(
+ mNavigationLight, animateChange());
}
}
@@ -268,10 +264,6 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
pw.println();
- if (mStatusBarIconController != null) {
- mStatusBarIconController.dump(fd, pw, args);
- }
-
LightBarTransitionsController transitionsController =
mStatusBarIconController.getTransitionsController();
if (transitionsController != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index dd07ec4c27dd..1944c3f21444 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -25,8 +25,8 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
-import android.util.MathUtils;
import android.provider.Settings;
+import android.util.MathUtils;
import android.util.TimeUtils;
import com.android.systemui.Dependency;
@@ -66,6 +66,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
private float mDarkIntensity;
private float mNextDarkIntensity;
private float mDozeAmount;
+ private int mDisplayId;
private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
@Override
public void run() {
@@ -85,6 +86,7 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
mStatusBarStateController.addCallback(this);
mDozeAmount = mStatusBarStateController.getDozeAmount();
mContext = context;
+ mDisplayId = mContext.getDisplayId();
}
public void destroy(Context context) {
@@ -104,15 +106,18 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
}
@Override
- public void appTransitionPending(boolean forced) {
- if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+ public void appTransitionPending(int displayId, boolean forced) {
+ if (mDisplayId != displayId || mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
return;
}
mTransitionPending = true;
}
@Override
- public void appTransitionCancelled() {
+ public void appTransitionCancelled(int displayId) {
+ if (mDisplayId != displayId) {
+ return;
+ }
if (mTransitionPending && mTintChangePending) {
mTintChangePending = false;
animateIconTint(mPendingDarkIntensity, 0 /* delay */, getTintAnimationDuration());
@@ -121,8 +126,9 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
}
@Override
- public void appTransitionStarting(long startTime, long duration, boolean forced) {
- if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+ public void appTransitionStarting(int displayId, long startTime, long duration,
+ boolean forced) {
+ if (mDisplayId != displayId || mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
return;
}
if (mTransitionPending && mTintChangePending) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 2daff2cb18bc..6d97d6724d40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -16,14 +16,21 @@ package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.WindowType;
+import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
@@ -72,6 +79,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.assist.AssistManager;
@@ -83,6 +91,8 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -111,6 +121,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
+ private static final long AUTODIM_TIMEOUT_MS = 2250;
private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
protected final AssistManager mAssistManager;
@@ -119,10 +130,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
protected NavigationBarView mNavigationBarView = null;
- private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
+ private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
private int mNavigationIconHints = 0;
- private int mNavigationBarMode;
+ private @TransitionMode int mNavigationBarMode;
private AccessibilityManager mAccessibilityManager;
private MagnificationContentObserver mMagnificationObserver;
private ContentResolver mContentResolver;
@@ -141,12 +152,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private int mSystemUiVisibility;
private LightBarController mLightBarController;
+ private AutoHideController mAutoHideController;
private OverviewProxyService mOverviewProxyService;
- private boolean mIsOnDefaultDisplay = true;
+ private int mDisplayId;
+ private boolean mIsOnDefaultDisplay;
public boolean mHomeBlockedThisTouch;
+ private Handler mHandler = Dependency.get(Dependency.MAIN_HANDLER);
+
private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
@Override
public void onConnectionChanged(boolean isConnected) {
@@ -183,17 +198,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
};
- private final ContextButtonListener mRotationButtonListener = new ContextButtonListener() {
- @Override
- public void onVisibilityChanged(ContextualButton button, boolean visible) {
- if (visible) {
- // If the button will actually become visible and the navbar is about to hide,
- // tell the statusbar to keep it around for longer
- mStatusBar.touchAutoHide();
- }
+ private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
+ if (visible) {
+ // If the button will actually become visible and the navbar is about to hide,
+ // tell the statusbar to keep it around for longer
+ mAutoHideController.touchAutoHide();
}
};
+ private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
+
@Inject
public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
@@ -251,7 +265,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
final Display display = view.getDisplay();
// It may not have display when running unit test.
if (display != null) {
- mIsOnDefaultDisplay = display.getDisplayId() == Display.DEFAULT_DISPLAY;
+ mDisplayId = display.getDisplayId();
+ mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
}
mNavigationBarView.setComponents(mStatusBar.getPanel());
@@ -351,8 +366,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
// ----- CommandQueue Callbacks -----
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
+ if (displayId != mDisplayId) {
+ return;
+ }
boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
int hints = mNavigationIconHints;
switch (backDisposition) {
@@ -381,19 +399,21 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
if (mNavigationBarView != null) {
mNavigationBarView.setNavigationIconHints(hints);
}
- mStatusBar.checkBarModes();
+ checkBarModes();
}
@Override
- public void topAppWindowChanged(boolean showMenu) {
- if (mNavigationBarView != null) {
+ public void topAppWindowChanged(int displayId, boolean showMenu) {
+ if (displayId == mDisplayId && mNavigationBarView != null) {
mNavigationBarView.setMenuVisibility(showMenu);
}
}
@Override
- public void setWindowState(int window, int state) {
- if (mNavigationBarView != null
+ public void setWindowState(
+ int displayId, @WindowType int window, @WindowVisibleState int state) {
+ if (displayId == mDisplayId
+ && mNavigationBarView != null
&& window == StatusBarManager.WINDOW_NAVIGATION_BAR
&& mNavigationBarWindowState != state) {
mNavigationBarWindowState = state;
@@ -426,28 +446,30 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
.onRotationProposal(rotation, winRotation, isValid);
}
- // Injected from StatusBar at creation.
- public void setCurrentSysuiVisibility(int systemUiVisibility) {
+ /**
+ * Sets System UI flags to {@link NavigationBarFragment}.
+ *
+ * @see View#setSystemUiVisibility(int)
+ */
+ public void setSystemUiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
- final int barMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
- View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
- View.NAVIGATION_BAR_TRANSPARENT);
+ final int barMode = computeBarMode(0, mSystemUiVisibility);
if (barMode != -1) {
mNavigationBarMode = barMode;
}
checkNavBarModes();
- mStatusBar.touchAutoHide();
+ mAutoHideController.touchAutoHide();
- // TODO(115978725): Support light bar controller on external nav bars.
- if (mLightBarController != null) {
- mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
- true /* nbModeChanged */, mNavigationBarMode);
- }
+ mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
+ true /* nbModeChanged */, mNavigationBarMode);
}
@Override
- public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ if (displayId != mDisplayId) {
+ return;
+ }
final int oldVal = mSystemUiVisibility;
final int newVal = (oldVal & ~mask) | (vis & mask);
final int diff = newVal ^ oldVal;
@@ -457,9 +479,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
// update navigation bar mode
final int nbMode = getView() == null
- ? -1 : mStatusBar.computeBarMode(oldVal, newVal,
- View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
- View.NAVIGATION_BAR_TRANSPARENT);
+ ? -1 : computeBarMode(oldVal, newVal);
nbModeChanged = nbMode != -1;
if (nbModeChanged) {
if (mNavigationBarMode != nbMode) {
@@ -470,19 +490,45 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mNavigationBarMode = nbMode;
checkNavBarModes();
}
- mStatusBar.touchAutoHide();
+ mAutoHideController.touchAutoHide();
}
}
+ mLightBarController.onNavigationVisibilityChanged(
+ vis, mask, nbModeChanged, mNavigationBarMode);
+ }
- // TODO(115978725): Support light bar controller on external nav bars.
- if (mLightBarController != null) {
- mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
- mNavigationBarMode);
+ private @TransitionMode int computeBarMode(int oldVis, int newVis) {
+ final int oldMode = barMode(oldVis);
+ final int newMode = barMode(newVis);
+ if (oldMode == newMode) {
+ return -1; // no mode change
+ }
+ return newMode;
+ }
+
+ private @TransitionMode int barMode(int vis) {
+ final int lightsOutTransparent =
+ View.SYSTEM_UI_FLAG_LOW_PROFILE | View.NAVIGATION_BAR_TRANSIENT;
+ if ((vis & View.NAVIGATION_BAR_TRANSIENT) != 0) {
+ return MODE_SEMI_TRANSPARENT;
+ } else if ((vis & View.NAVIGATION_BAR_TRANSLUCENT) != 0) {
+ return MODE_TRANSLUCENT;
+ } else if ((vis & lightsOutTransparent) == lightsOutTransparent) {
+ return MODE_LIGHTS_OUT_TRANSPARENT;
+ } else if ((vis & View.NAVIGATION_BAR_TRANSPARENT) != 0) {
+ return MODE_TRANSPARENT;
+ } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+ return MODE_LIGHTS_OUT;
+ } else {
+ return MODE_OPAQUE;
}
}
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != mDisplayId) {
+ return;
+ }
// Navigation bar flags are in both state1 and state2.
final int masked = state1 & (StatusBarManager.DISABLE_HOME
| StatusBarManager.DISABLE_RECENT
@@ -511,7 +557,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
}
- // ----- Internal stuffz -----
+ // ----- Internal stuff -----
private void refreshLayout(int layoutDirection) {
if (mNavigationBarView != null) {
@@ -610,7 +656,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
private boolean onNavigationTouch(View v, MotionEvent event) {
- mStatusBar.checkUserAutohide(event);
+ mAutoHideController.checkUserAutoHide(event);
return false;
}
@@ -800,30 +846,69 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
}
- // ----- Methods that StatusBar talks to (should be minimized) -----
+ // ----- Methods that DisplayNavigationBarController talks to -----
+
+ /** Applies auto dimming animation on navigation bar when touched. */
+ public void touchAutoDim() {
+ getBarTransitions().setAutoDim(false);
+ mHandler.removeCallbacks(mAutoDim);
+ int state = Dependency.get(StatusBarStateController.class).getState();
+ if (state != StatusBarState.KEYGUARD && state != StatusBarState.SHADE_LOCKED) {
+ mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
+ }
+ }
public void setLightBarController(LightBarController lightBarController) {
mLightBarController = lightBarController;
mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
}
+ /** Sets {@link AutoHideController} to the navigation bar. */
+ public void setAutoHideController(AutoHideController autoHideController) {
+ mAutoHideController = autoHideController;
+ mAutoHideController.setNavigationBar(this);
+ }
+
public boolean isSemiTransparent() {
return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
}
+ private void checkBarModes() {
+ // We only have status bar on default display now.
+ if (mIsOnDefaultDisplay) {
+ mStatusBar.checkBarModes();
+ } else {
+ checkNavBarModes();
+ }
+ }
+
+ /**
+ * Checks current navigation bar mode and make transitions.
+ */
+ public void checkNavBarModes() {
+ final boolean anim = mStatusBar.isDeviceInteractive()
+ && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
+ mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
+ }
+
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
}
- public BarTransitions getBarTransitions() {
- return mNavigationBarView.getBarTransitions();
+ /**
+ * Performs transitions on navigation bar.
+ *
+ * @param barMode transition bar mode.
+ * @param animate shows animations if {@code true}.
+ */
+ public void transitionTo(@TransitionMode int barMode, boolean animate) {
+ getBarTransitions().transitionTo(barMode, animate);
}
- public void checkNavBarModes() {
- mStatusBar.checkBarMode(mNavigationBarMode,
- mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
+ private BarTransitions getBarTransitions() {
+ return mNavigationBarView.getBarTransitions();
}
public void finishBarAnimations() {
@@ -873,12 +958,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
// The accessibility settings may be different for the new user
updateAccessibilityServicesState(mAccessibilityManager);
- };
+ }
}
};
public static View create(Context context, FragmentListener listener) {
- final int displayId = context.getDisplay().getDisplayId();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
@@ -890,7 +974,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
- lp.setTitle("NavigationBar" + displayId);
+ lp.setTitle("NavigationBar" + context.getDisplayId());
lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 8c17922a4f0c..2fc7b78c0ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -282,6 +282,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
@Override
+ public void onHomeButtonVisibilityChanged(boolean visible) {
+ getHomeButton().setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ @Override
public void onColorAdaptChanged(boolean enabled) {
if (enabled) {
mColorAdaptionController.start();
@@ -672,6 +677,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
// TODO(b/113914868): investigation log for disappearing home button
Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
+ " mDisabledFlags=" + mDisabledFlags);
+ disableHome |= mPrototypeController.hideHomeButton();
// Always disable recents when alternate car mode UI is active and for secondary displays.
boolean disableRecent = isRecentsButtonDisabled();
@@ -945,6 +951,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
// TODO(b/112934365): remove after prototype finished, only needed to escape from pin
getBackButton().setVisibility(VISIBLE);
+ getHomeButton().setVisibility(VISIBLE);
} else {
mScreenPinningNotify.showPinningExitToast();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index 40ac79376b06..fb6254b0e4be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -34,6 +34,7 @@ import java.lang.annotation.RetentionPolicy;
*/
public class NavigationPrototypeController extends ContentObserver {
private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
+ private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
@@ -73,6 +74,7 @@ public class NavigationPrototypeController extends ContentObserver {
*/
public void register() {
registerObserver(HIDE_BACK_BUTTON_SETTING);
+ registerObserver(HIDE_HOME_BUTTON_SETTING);
registerObserver(GESTURE_MATCH_SETTING);
registerObserver(NAV_COLOR_ADAPT_ENABLE_SETTING);
}
@@ -88,22 +90,20 @@ public class NavigationPrototypeController extends ContentObserver {
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (!selfChange && mListener != null) {
- try {
- final String path = uri.getPath();
- if (path.endsWith(GESTURE_MATCH_SETTING)) {
- // Get the settings gesture map corresponding to each action
- // {@see updateSwipeLTRBackSetting}
- updateSwipeLTRBackSetting();
- mListener.onGestureRemap(mActionMap);
- } else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
- mListener.onBackButtonVisibilityChanged(
- !getGlobalBool(HIDE_BACK_BUTTON_SETTING));
- } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
- mListener.onColorAdaptChanged(
- NavBarTintController.isEnabled(mContext));
- }
- } catch (SettingNotFoundException e) {
- e.printStackTrace();
+ final String path = uri.getPath();
+ if (path.endsWith(GESTURE_MATCH_SETTING)) {
+ // Get the settings gesture map corresponding to each action
+ // {@see updateSwipeLTRBackSetting}
+ updateSwipeLTRBackSetting();
+ mListener.onGestureRemap(mActionMap);
+ } else if (path.endsWith(HIDE_BACK_BUTTON_SETTING)) {
+ mListener.onBackButtonVisibilityChanged(
+ !getGlobalBool(HIDE_BACK_BUTTON_SETTING, false));
+ } else if (path.endsWith(HIDE_HOME_BUTTON_SETTING)) {
+ mListener.onHomeButtonVisibilityChanged(!hideHomeButton());
+ } else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
+ mListener.onColorAdaptChanged(
+ NavBarTintController.isEnabled(mContext));
}
}
}
@@ -117,6 +117,13 @@ public class NavigationPrototypeController extends ContentObserver {
}
/**
+ * @return if home button should be invisible
+ */
+ boolean hideHomeButton() {
+ return getGlobalBool(HIDE_HOME_BUTTON_SETTING, false /* default */);
+ }
+
+ /**
* Since Settings.Global cannot pass arrays, use a string to represent each character as a
* gesture map to actions corresponding to {@see GestureAction}. The number is represented as:
* Number: [up] [down] [left] [right]
@@ -131,8 +138,8 @@ public class NavigationPrototypeController extends ContentObserver {
}
}
- private boolean getGlobalBool(String name) throws SettingNotFoundException {
- return Settings.Global.getInt(mContext.getContentResolver(), name) == 1;
+ private boolean getGlobalBool(String name, boolean defaultVal) {
+ return Settings.Global.getInt(mContext.getContentResolver(), name, defaultVal ? 1 : 0) == 1;
}
private void registerObserver(String name) {
@@ -143,6 +150,7 @@ public class NavigationPrototypeController extends ContentObserver {
public interface OnPrototypeChangedListener {
void onGestureRemap(@GestureAction int[] actions);
void onBackButtonVisibilityChanged(boolean visible);
+ void onHomeButtonVisibilityChanged(boolean visible);
void onColorAdaptChanged(boolean enabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 1a783025d405..af3257ae423e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.phone;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AmbientPulseManager;
@@ -217,15 +219,13 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
@Override
public void onEntryRemoved(
- Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ @Nullable Entry entry,
+ NotificationVisibility visibility,
boolean removedByUser) {
// Removes any alerts pending on this entry. Note that this will not stop any inflation
// tasks started by a transfer, so this should only be used as clean-up for when
// inflation is stopped and the pending alert no longer needs to happen.
- mPendingAlerts.remove(key);
+ mPendingAlerts.remove(entry.key);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e40835fb8fd0..056c8a7f5f5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -19,14 +19,14 @@ import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 1b18c6cf8440..16576ad6e3e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -312,6 +312,7 @@ public class NotificationPanelView extends PanelView implements
Dependency.get(NotificationLockscreenUserManager.class);
private final ShadeController mShadeController =
Dependency.get(ShadeController.class);
+ private int mDisplayId;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -323,6 +324,7 @@ public class NotificationPanelView extends PanelView implements
mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
setPanelAlpha(255, false /* animate */);
mCommandQueue = getComponent(context, CommandQueue.class);
+ mDisplayId = context.getDisplayId();
}
private void setStatusBar(StatusBar bar) {
@@ -2596,7 +2598,7 @@ public class NotificationPanelView extends PanelView implements
}
if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
mShowIconsWhenExpanded = showIconsWhenExpanded;
- mCommandQueue.recomputeDisableFlags(false);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, false);
}
}
@@ -2803,6 +2805,11 @@ public class NotificationPanelView extends PanelView implements
if (animatePulse) {
mAnimateNextPositionUpdate = true;
}
+ // Do not animate the clock when waking up from a pulse.
+ // The height callback will take care of pushing the clock to the right position.
+ if (!mPulsing && !mDozing) {
+ mAnimateNextPositionUpdate = false;
+ }
mNotificationStackScroller.setPulsing(pulsing, animatePulse);
mKeyguardStatusView.setPulsing(pulsing, animatePulse);
mKeyguardBottomArea.setPulsing(pulsing, animatePulse);
@@ -2856,7 +2863,7 @@ public class NotificationPanelView extends PanelView implements
if (hideIcons != mHideIconsDuringNotificationLaunch) {
mHideIconsDuringNotificationLaunch = hideIcons;
if (!hideIcons) {
- mCommandQueue.recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d6f2fd7a4eee..43c35f11d9e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -736,9 +736,12 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
};
@Override
- public void appTransitionStarting(long startTime, long duration, boolean forced) {
- updateManagedProfile();
- updateForegroundInstantApps();
+ public void appTransitionStarting(int displayId, long startTime, long duration,
+ boolean forced) {
+ if (mContext.getDisplayId() == displayId) {
+ updateManagedProfile();
+ updateForegroundInstantApps();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 2129835945d7..7a3d03fec025 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -43,9 +43,9 @@ import android.widget.LinearLayout;
import com.android.systemui.Dependency;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import java.util.Objects;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index efe734eb9cec..977e33688831 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,9 +20,10 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.WindowType;
+import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -37,6 +38,7 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRAN
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
+import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -71,7 +73,6 @@ import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
@@ -79,6 +80,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -155,6 +157,8 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.qs.QSFragment;
@@ -168,11 +172,11 @@ import com.android.systemui.statusbar.AmbientPulseManager;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.DisplayNavigationBarController;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -204,7 +208,6 @@ import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChang
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.ExtensionController;
@@ -288,10 +291,6 @@ public class StatusBar extends SystemUI implements DemoMode,
protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
- private static final int STATUS_OR_NAV_TRANSIENT =
- View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
- private static final long AUTOHIDE_TIMEOUT_MS = 2250;
-
/**
* The delay to reset the hint text when the hint animation is finished running.
*/
@@ -340,6 +339,8 @@ public class StatusBar extends SystemUI implements DemoMode,
protected BiometricUnlockController mBiometricUnlockController;
private LightBarController mLightBarController;
protected LockscreenWallpaper mLockscreenWallpaper;
+ @VisibleForTesting
+ protected AutoHideController mAutoHideController;
private int mNaturalBarHeight = -1;
@@ -404,9 +405,6 @@ public class StatusBar extends SystemUI implements DemoMode,
private final Rect mLastFullscreenStackBounds = new Rect();
private final Rect mLastDockedStackBounds = new Rect();
- // last value sent to window manager
- private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
// XXX: gesture research
@@ -446,21 +444,13 @@ public class StatusBar extends SystemUI implements DemoMode,
protected final H mHandler = createHandler();
private int mInteractingWindows;
- private boolean mAutohideSuspended;
- private int mStatusBarMode;
+ private @TransitionMode int mStatusBarMode;
private ViewMediatorCallback mKeyguardViewMediatorCallback;
protected ScrimController mScrimController;
protected DozeScrimController mDozeScrimController;
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
- private final Runnable mAutohide = () -> {
- int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
- if (mSystemUiVisibility != requested) {
- notifyUiVisibilityChanged(requested);
- }
- };
-
protected boolean mDozing;
private boolean mDozingRequested;
@@ -583,11 +573,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mEntryManager.updateNotifications();
}
};
-
- protected DisplayManager mDisplayManager;
-
- private NavigationBarFragment mNavigationBar;
- private View mNavigationBarView;
+ private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private boolean mVibrateOnOpening;
@@ -642,7 +628,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- mNavigationBarController = Dependency.get(DisplayNavigationBarController.class);
+ mNavigationBarController = Dependency.get(NavigationBarController.class);
mBubbleController = Dependency.get(BubbleController.class);
mBubbleController.setExpandListener(mBubbleExpandListener);
KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
@@ -660,6 +646,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ServiceManager.checkService(DreamService.DREAM_SERVICE));
mDisplay = mWindowManager.getDefaultDisplay();
+ mDisplayId = mDisplay.getDisplayId();
updateDisplaySize();
Resources res = mContext.getResources();
@@ -715,11 +702,11 @@ public class StatusBar extends SystemUI implements DemoMode,
// Set up the initial notification state. This needs to happen before CommandQueue.disable()
setUpPresenter();
- setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
+ setSystemUiVisibility(mDisplayId, switches[1], switches[7], switches[8], 0xffffffff,
fullscreenStackBounds, dockedStackBounds);
- topAppWindowChanged(switches[2] != 0);
+ topAppWindowChanged(mDisplayId, switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
+ setImeWindowStatus(mDisplayId, binders.get(0), switches[3], switches[4], switches[5] != 0);
// Set up the initial icon state
int N = iconSlots.size();
@@ -808,6 +795,9 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationIconAreaController.setupShelf(mNotificationShelf);
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
+ // Allow plugins to reference DarkIconDispatcher
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(DarkIconDispatcher.class);
FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
@@ -868,6 +858,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
+ mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
putComponent(HeadsUpManager.class, mHeadsUpManager);
createNavigationBar();
@@ -902,11 +893,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
});
- // TODO(115978725): Support light bar controller on external nav bars.
+ mAutoHideController = Dependency.get(AutoHideController.class);
+ mAutoHideController.setStatusBar(this);
+
mLightBarController = Dependency.get(LightBarController.class);
- if (mNavigationBar != null) {
- mNavigationBar.setLightBarController(mLightBarController);
- }
ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
@@ -1065,7 +1055,7 @@ public class StatusBar extends SystemUI implements DemoMode,
* @param state2 disable2 flags
*/
protected void setUpDisableFlags(int state1, int state2) {
- mCommandQueue.disable(state1, state2, false /* animate */);
+ mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */);
}
@Override
@@ -1092,25 +1082,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
+ // TODO(b/117478341): This was left such that CarStatusBar can override this method.
+ // Try to remove this.
protected void createNavigationBar() {
- try {
- // TODO(117478341): Move this into DisplayNavigationBarController#createNavigationBars
- // for-loop. We will also move the whole navigation bar logic together.
- final boolean showNav = mWindowManagerService.hasNavigationBar(DEFAULT_DISPLAY);
- if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
- if (!showNav) return;
-
- mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
- mNavigationBar = (NavigationBarFragment) fragment;
- if (mLightBarController != null) {
- mNavigationBar.setLightBarController(mLightBarController);
- }
- mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
- });
- } catch (RemoteException ex) {
- // no window manager? good luck with that
- }
- mNavigationBarController.createNavigationBars();
+ mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */);
}
/**
@@ -1119,7 +1094,7 @@ public class StatusBar extends SystemUI implements DemoMode,
*/
protected View.OnTouchListener getStatusBarWindowTouchListener() {
return (v, event) -> {
- checkUserAutohide(event);
+ mAutoHideController.checkUserAutoHide(event);
mRemoteInputManager.checkRemoteInputOutside(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mExpandedVisible) {
@@ -1254,8 +1229,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
int dockSide = WindowManagerProxy.getInstance().getDockSide();
if (dockSide == WindowManager.DOCKED_INVALID) {
- final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(
- mDisplay.getDisplayId());
+ final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
if (navbarPos == NAV_BAR_POS_INVALID) {
return false;
}
@@ -1364,7 +1338,10 @@ public class StatusBar extends SystemUI implements DemoMode,
* State is one or more of the DISABLE constants from StatusBarManager.
*/
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != mDisplayId) {
+ return;
+ }
state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
@@ -1642,10 +1619,10 @@ public class StatusBar extends SystemUI implements DemoMode,
mWereIconsJustHidden = true;
mHandler.postDelayed(() -> {
mWereIconsJustHidden = false;
- mCommandQueue.recomputeDisableFlags(true);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true);
}, 500);
} else {
- mCommandQueue.recomputeDisableFlags(animate);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, animate);
}
}
if (shouldHideIconsForBouncer) {
@@ -1811,7 +1788,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarWindowController.setPanelVisible(true);
visibilityChanged(true);
- mCommandQueue.recomputeDisableFlags(!force /* animate */);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, !force /* animate */);
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
}
@@ -1984,7 +1961,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
}
mCommandQueue.recomputeDisableFlags(
- mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
+ mDisplayId, mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -2041,7 +2018,11 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override // CommandQueue
- public void setWindowState(int window, int state) {
+ public void setWindowState(
+ int displayId, @WindowType int window, @WindowVisibleState int state) {
+ if (displayId != mDisplayId) {
+ return;
+ }
boolean showing = state == WINDOW_STATE_SHOWING;
if (mStatusBarWindow != null
&& window == StatusBarManager.WINDOW_STATUS_BAR
@@ -2060,14 +2041,17 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override // CommandQueue
- public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ if (displayId != mDisplayId) {
+ return;
+ }
final int oldVal = mSystemUiVisibility;
final int newVal = (oldVal&~mask) | (vis&mask);
final int diff = newVal ^ oldVal;
if (DEBUG) Log.d(TAG, String.format(
- "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
- Integer.toHexString(vis), Integer.toHexString(mask),
+ "setSystemUiVisibility displayId=%d vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
+ displayId, Integer.toHexString(vis), Integer.toHexString(mask),
Integer.toHexString(oldVal), Integer.toHexString(newVal),
Integer.toHexString(diff)));
boolean sbModeChanged = false;
@@ -2081,7 +2065,6 @@ public class StatusBar extends SystemUI implements DemoMode,
// ready to unhide
if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
- mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
mNoAnimationOnNextBarModeChange = true;
}
@@ -2092,17 +2075,9 @@ public class StatusBar extends SystemUI implements DemoMode,
if (sbModeChanged && sbMode != mStatusBarMode) {
mStatusBarMode = sbMode;
checkBarModes();
- touchAutoHide();
+ mAutoHideController.touchAutoHide();
}
-
- if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
- mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
- }
-
- // send updated sysui visibility to window manager
- notifyUiVisibilityChanged(mSystemUiVisibility);
}
-
mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
}
@@ -2130,52 +2105,45 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- // TODO(115978725): Support auto hide on external nav bars.
- void touchAutoHide() {
- // update transient bar autohide
- if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
- && mNavigationBar.isSemiTransparent())) {
- scheduleAutohide();
- } else {
- cancelAutohide();
- }
- }
-
- protected int computeStatusBarMode(int oldVal, int newVal) {
- return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
- View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
+ protected @TransitionMode int computeStatusBarMode(int oldVal, int newVal) {
+ return computeBarMode(oldVal, newVal);
}
protected BarTransitions getStatusBarTransitions() {
return mStatusBarView.getBarTransitions();
}
- protected int computeBarMode(int oldVis, int newVis,
- int transientFlag, int translucentFlag, int transparentFlag) {
- final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
- final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
+ protected @TransitionMode int computeBarMode(int oldVis, int newVis) {
+ final int oldMode = barMode(oldVis);
+ final int newMode = barMode(newVis);
if (oldMode == newMode) {
return -1; // no mode change
}
return newMode;
}
- private int barMode(int vis, int transientFlag, int translucentFlag, int transparentFlag) {
- int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | transparentFlag;
- return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
- : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
- : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
- : (vis & transparentFlag) != 0 ? MODE_TRANSPARENT
- : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
- : MODE_OPAQUE;
+ private @TransitionMode int barMode(int vis) {
+ int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.STATUS_BAR_TRANSPARENT;
+ if ((vis & View.STATUS_BAR_TRANSIENT) != 0) {
+ return MODE_SEMI_TRANSPARENT;
+ } else if ((vis & View.STATUS_BAR_TRANSLUCENT) != 0) {
+ return MODE_TRANSLUCENT;
+ } else if ((vis & lightsOutTransparent) == lightsOutTransparent) {
+ return MODE_LIGHTS_OUT_TRANSPARENT;
+ } else if ((vis & View.STATUS_BAR_TRANSPARENT) != 0) {
+ return MODE_TRANSPARENT;
+ } else if ((vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+ return MODE_LIGHTS_OUT;
+ } else {
+ return MODE_OPAQUE;
+ }
}
- // TODO(115978725): Support animations on external nav bars.
void checkBarModes() {
if (mDemoMode) return;
if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
getStatusBarTransitions());
- if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
+ mNavigationBarController.checkNavBarModes(mDisplayId);
mNoAnimationOnNextBarModeChange = false;
}
@@ -2184,20 +2152,18 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.setQsScrimEnabled(scrimEnabled);
}
- void checkBarMode(int mode, int windowState, BarTransitions transitions) {
+ void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
+ BarTransitions transitions) {
final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
&& windowState != WINDOW_STATE_HIDDEN;
transitions.transitionTo(mode, anim);
}
- // TODO(115978725): Support animations on external nav bars.
private void finishBarAnimations() {
if (mStatusBarView != null) {
mStatusBarView.getBarTransitions().finishAnimations();
}
- if (mNavigationBar != null) {
- mNavigationBar.finishBarAnimations();
- }
+ mNavigationBarController.finishBarAnimations(mDisplayId);
}
private final Runnable mCheckBarModes = this::checkBarModes;
@@ -2208,13 +2174,13 @@ public class StatusBar extends SystemUI implements DemoMode,
? (mInteractingWindows | barWindow)
: (mInteractingWindows & ~barWindow);
if (mInteractingWindows != 0) {
- suspendAutohide();
+ mAutoHideController.suspendAutoHide();
} else {
- resumeSuspendedAutohide();
+ mAutoHideController.resumeSuspendedAutoHide();
}
// manually dismiss the volume panel when interacting with the nav bar
if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
- touchAutoDim();
+ mNavigationBarController.touchAutoDim(mDisplayId);
dismissVolumeDialog();
}
checkBarModes();
@@ -2226,59 +2192,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- private void resumeSuspendedAutohide() {
- if (mAutohideSuspended) {
- scheduleAutohide();
- mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
- }
- }
-
- private void suspendAutohide() {
- mHandler.removeCallbacks(mAutohide);
- mHandler.removeCallbacks(mCheckBarModes);
- mAutohideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
- }
-
- private void cancelAutohide() {
- mAutohideSuspended = false;
- mHandler.removeCallbacks(mAutohide);
- }
-
- private void scheduleAutohide() {
- cancelAutohide();
- mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
- }
-
- public void touchAutoDim() {
- if (mNavigationBar != null) {
- mNavigationBar.getBarTransitions().setAutoDim(false);
- }
- mHandler.removeCallbacks(mAutoDim);
-
- // Do not dim the navigation buttons if the its tint is controlled by the bar's background
- if (NavBarTintController.isEnabled(mContext)) {
- return;
- }
- if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
- mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
- }
- }
-
- void checkUserAutohide(MotionEvent event) {
- if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
- && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
- && event.getX() == 0 && event.getY() == 0 // a touch outside both bars
- && !mRemoteInputManager.getController()
- .isRemoteInputActive()) { // not due to typing in IME
- userAutohide();
- }
- }
-
- private void userAutohide() {
- cancelAutohide();
- mHandler.postDelayed(mAutohide, 350); // longer than app gesture -> flag clear
- }
-
private boolean areLightsOn() {
return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
@@ -2286,30 +2199,21 @@ public class StatusBar extends SystemUI implements DemoMode,
public void setLightsOn(boolean on) {
Log.v(TAG, "setLightsOn(" + on + ")");
if (on) {
- setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
+ setSystemUiVisibility(mDisplayId, 0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
mLastFullscreenStackBounds, mLastDockedStackBounds);
} else {
- setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
+ setSystemUiVisibility(mDisplayId, View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
mLastDockedStackBounds);
}
}
- private void notifyUiVisibilityChanged(int vis) {
- try {
- if (mLastDispatchedSystemUiVisibility != vis) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- mWindowManagerService.statusBarVisibilityChanged(Display.DEFAULT_DISPLAY, vis);
- mLastDispatchedSystemUiVisibility = vis;
- }
- } catch (RemoteException ex) {
- }
- }
-
@Override
- public void topAppWindowChanged(boolean showMenu) {
+ public void topAppWindowChanged(int displayId, boolean showMenu) {
+ if (mDisplayId != displayId) return;
if (SPEW) {
- Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
+ Log.d(TAG, "display#" + displayId + ": "
+ + (showMenu ? "showing" : "hiding") + " the MENU button");
}
// See above re: lights-out policy for legacy apps.
@@ -2924,10 +2828,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mWindowManager.removeViewImmediate(mStatusBarWindow);
mStatusBarWindow = null;
}
- if (mNavigationBarView != null) {
- mWindowManager.removeViewImmediate(mNavigationBarView);
- mNavigationBarView = null;
- }
mNavigationBarController.destroy();
mContext.unregisterReceiver(mBroadcastReceiver);
mContext.unregisterReceiver(mDemoReceiver);
@@ -2997,15 +2897,12 @@ public class StatusBar extends SystemUI implements DemoMode,
"transparent".equals(mode) ? MODE_TRANSPARENT :
"warning".equals(mode) ? MODE_WARNING :
-1;
- // TODO(115978725): Support external nav bar transitions
if (barMode != -1) {
boolean animate = true;
if (mStatusBarView != null) {
mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
}
- if (mNavigationBar != null) {
- mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
- }
+ mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
}
}
if (modeChange || command.equals(COMMAND_OPERATOR)) {
@@ -3143,7 +3040,7 @@ public class StatusBar extends SystemUI implements DemoMode,
.setDuration(FADE_KEYGUARD_DURATION)
.withLayer()
.withEndAction(this::onLaunchTransitionFadingEnded);
- mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
+ mCommandQueue.appTransitionStarting(mDisplayId, SystemClock.uptimeMillis(),
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
};
if (mNotificationPanel.isLaunchTransitionRunning()) {
@@ -3231,12 +3128,9 @@ public class StatusBar extends SystemUI implements DemoMode,
mDraggedDownEntry = null;
}
- // TODO(115978725): Support animations on external nav bars.
// Disable layout transitions in navbar for this transition because the load is just
// too heavy for the CPU and GPU on any device.
- if (mNavigationBar != null) {
- mNavigationBar.disableAnimationsDuringHide(delay);
- }
+ mNavigationBarController.disableAnimationsDuringHide(mDisplayId, delay);
} else if (!mNotificationPanel.isCollapsing()) {
instantCollapseNotificationPanel();
}
@@ -3269,7 +3163,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// Treat Keyguard exit animation as an app transition to achieve nice transition for status
// bar.
mKeyguardMonitor.notifyKeyguardGoingAway(true);
- mCommandQueue.appTransitionPending(true);
+ mCommandQueue.appTransitionPending(mDisplayId, true /* forced */);
}
/**
@@ -3280,11 +3174,11 @@ public class StatusBar extends SystemUI implements DemoMode,
* @param fadeoutDuration the duration of the exit animation, in milliseconds
*/
public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
- mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
+ mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
- LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
- mCommandQueue.recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
- mCommandQueue.appTransitionStarting(
+ mCommandQueue.recomputeDisableFlags(mDisplayId, fadeoutDuration > 0 /* animate */);
+ mCommandQueue.appTransitionStarting(mDisplayId,
startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
@@ -3410,7 +3304,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// Make our window larger and the panel expanded.
makeExpandedVisible(true);
mNotificationPanel.expand(false /* animate */);
- mCommandQueue.recomputeDisableFlags(false /* animate */);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
}
@Override
@@ -3466,7 +3360,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateReportRejectedTouchVisibility();
updateDozing();
updateTheme();
- touchAutoDim();
+ mNavigationBarController.touchAutoDim(mDisplayId);
Trace.beginSection("StatusBar#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
@@ -3587,11 +3481,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// TODO: Figure out way to remove these.
public NavigationBarView getNavigationBarView() {
- return (mNavigationBar != null ? (NavigationBarView) mNavigationBar.getView() : null);
- }
-
- public View getNavigationBarWindow() {
- return mNavigationBarView;
+ return mNavigationBarController.getDefaultNavigationBarView();
}
/**
@@ -3655,7 +3545,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mBouncerShowing = bouncerShowing;
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
- mCommandQueue.recomputeDisableFlags(true /* animate */);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
updateScrimController();
}
@@ -3780,13 +3670,17 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
- public void appTransitionCancelled() {
- getComponent(Divider.class).onAppTransitionFinished();
+ public void appTransitionCancelled(int displayId) {
+ if (displayId == mDisplayId) {
+ getComponent(Divider.class).onAppTransitionFinished();
+ }
}
@Override
- public void appTransitionFinished() {
- getComponent(Divider.class).onAppTransitionFinished();
+ public void appTransitionFinished(int displayId) {
+ if (displayId == mDisplayId) {
+ getComponent(Divider.class).onAppTransitionFinished();
+ }
}
@Override
@@ -4173,7 +4067,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private DeviceProvisionedController mDeviceProvisionedController
= Dependency.get(DeviceProvisionedController.class);
- protected DisplayNavigationBarController mNavigationBarController;
+ protected NavigationBarController mNavigationBarController;
// UI-specific methods
@@ -4182,6 +4076,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private IDreamManager mDreamManager;
protected Display mDisplay;
+ private int mDisplayId;
protected Recents mRecents;
@@ -4309,7 +4204,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// Immediately update the icon hidden state, since that should only apply if we're
// staying fullscreen.
mWereIconsJustHidden = false;
- mCommandQueue.recomputeDisableFlags(true);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true);
}
updateHideIconsForBouncer(true /* animate */);
}
@@ -4368,7 +4263,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void startPendingIntentDismissingKeyguard(
- final PendingIntent intent, @Nullable final Runnable intentSentCallback) {
+ final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
@@ -4387,12 +4282,16 @@ public class StatusBar extends SystemUI implements DemoMode,
if (intent.isActivity()) {
mAssistManager.hideAssist();
}
- if (intentSentCallback != null) {
- intentSentCallback.run();
+ if (intentSentUiThreadCallback != null) {
+ postOnUiThread(intentSentUiThreadCallback);
}
}, afterKeyguardGone);
}
+ private void postOnUiThread(Runnable runnable) {
+ mMainThreadHandler.post(runnable);
+ }
+
public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
ActivityOptions options;
if (animationAdapter != null) {
@@ -4501,13 +4400,6 @@ public class StatusBar extends SystemUI implements DemoMode,
}
// End Extra BaseStatusBarMethods.
- // TODO(115978725): Handle dimming for external nav bars
- private final Runnable mAutoDim = () -> {
- if (mNavigationBar != null) {
- mNavigationBar.getBarTransitions().setAutoDim(true);
- }
- };
-
public NotificationGutsManager getGutsManager() {
return mGutsManager;
}
@@ -4516,4 +4408,8 @@ public class StatusBar extends SystemUI implements DemoMode,
public interface StatusBarInjector {
void createStatusBar(StatusBar statusbar);
}
+
+ public @TransitionMode int getStatusBarMode() {
+ return mStatusBarMode;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 26c9d288494d..2e2ff1a5750e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -38,14 +38,14 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.util.Utils.DisableStateTracker;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 252b92c2f37f..fb3157a128d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
+import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -37,10 +38,12 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingMessage;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
@@ -192,23 +195,27 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
@Override
public void onEntryRemoved(
- Entry entry,
- String key,
- StatusBarNotification old,
- boolean lifetimeExtended,
+ @Nullable Entry entry,
+ NotificationVisibility visibility,
boolean removedByUser) {
- if (!lifetimeExtended) {
- StatusBarNotificationPresenter.this.onNotificationRemoved(key, old);
- }
+ StatusBarNotificationPresenter.this.onNotificationRemoved(
+ entry.key, entry.notification);
if (removedByUser) {
maybeEndAmbientPulse();
}
}
};
+ NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
+
mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
mEntryManager.setUpWithPresenter(this, notifListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(notificationEntryListener);
+ mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
+ mEntryManager.addNotificationLifetimeExtender(mAmbientPulseManager);
+ mEntryManager.addNotificationLifetimeExtender(gutsManager);
+ mEntryManager.addNotificationLifetimeExtenders(
+ remoteInputManager.getLifetimeExtenders());
mNotificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
mEntryManager, this);
mNotificationInterruptionStateProvider.setUpWithPresenter(
@@ -216,8 +223,12 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mLockscreenUserManager.setUpWithPresenter(this);
mMediaManager.setUpWithPresenter(this);
mVisualStabilityManager.setUpWithPresenter(this);
- Dependency.get(NotificationGutsManager.class).setUpWithPresenter(this,
+ gutsManager.setUpWithPresenter(this,
notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
+ // ForegroundServiceControllerListener adds its listener in its constructor
+ // but we need to request it here in order for it to be instantiated.
+ // TODO: figure out how to do this correctly once Dependency.get() is gone.
+ Dependency.get(ForegroundServiceNotificationListener.class);
onUserSwitched(mLockscreenUserManager.getCurrentUserId());
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 116ecc8ddeb5..3ddfc0c81c60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -238,8 +238,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks {
}
@Override
- public void disable(int state1, int state2, boolean animate) {
- mDisabled2 = state2;
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId == mContext.getDisplayId()) {
+ mDisabled2 = state2;
+ }
}
protected class ChallengeReceiver extends BroadcastReceiver {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
new file mode 100644
index 000000000000..d53772127601
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.plugins.DarkIconDispatcher;
+
+/**
+ * Dispatches events to {@link DarkReceiver}s about changes in darkness, tint area
+ * and dark intensity.
+ */
+public interface SysuiDarkIconDispatcher extends DarkIconDispatcher, Dumpable {
+
+ /**
+ * @return LightBarTransitionsController
+ */
+ LightBarTransitionsController getTransitionsController();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index aafdcd50b8e8..de7ef3ba645d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -44,11 +44,12 @@ import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -298,7 +299,10 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
}
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != getDisplay().getDisplayId()) {
+ return;
+ }
boolean clockVisibleByPolicy = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
if (clockVisibleByPolicy != mClockVisibleByPolicy) {
setClockVisibilityByPolicy(clockVisibleByPolicy);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 4a1175489c5e..54502e41ca64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -24,10 +24,10 @@ import android.util.Slog;
import android.view.MotionEvent;
import android.view.Surface;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.phone.NavigationBarView;
-import com.android.systemui.statusbar.phone.StatusBar;
/**
* The "dead zone" consumes unintentional taps along the top edge of the navigation bar.
@@ -44,7 +44,7 @@ public class DeadZone {
public static final int VERTICAL = 1; // Consume taps along the left edge.
private static final boolean CHATTY = true; // print to logcat when we eat a click
- private final StatusBar mStatusBar;
+ private final NavigationBarController mNavBarController;
private final NavigationBarView mNavigationBarView;
private boolean mShouldFlash;
@@ -58,6 +58,7 @@ public class DeadZone {
private boolean mVertical;
private long mLastPokeTime;
private int mDisplayRotation;
+ private final int mDisplayId;
private final Runnable mDebugFlash = new Runnable() {
@Override
@@ -68,8 +69,8 @@ public class DeadZone {
public DeadZone(NavigationBarView view) {
mNavigationBarView = view;
- mStatusBar = SysUiServiceProvider.getComponent(mNavigationBarView.getContext(),
- StatusBar.class);
+ mNavBarController = Dependency.get(NavigationBarController.class);
+ mDisplayId = view.getContext().getDisplayId();
onConfigurationChanged(HORIZONTAL);
}
@@ -133,7 +134,7 @@ public class DeadZone {
if (DEBUG) {
Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
- if (mStatusBar != null) mStatusBar.touchAutoDim();
+ mNavBarController.touchAutoDim(mDisplayId);
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 2c756ceb1b48..d4049826a50a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -33,6 +33,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
@@ -304,6 +305,10 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
.setSubtype(mCode)
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
+ // TODO(b/122195391): Added logs to make sure sysui is sending back button events
+ if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
+ Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
+ }
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
index 630bd18c6ad6..2b602742e309 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -82,6 +82,6 @@ public class RemoteInputQuickSettingsDisabler
* to modify the disable flags according to the status of mRemoteInputActive and misLandscape.
*/
private void recomputeDisableFlags() {
- mCommandQueue.recomputeDisableFlags(true);
+ mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), true);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 4fa8321fa1e9..f85d8038ab3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -16,8 +16,6 @@ import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.text.Layout;
import android.text.TextPaint;
import android.text.method.TransformationMethod;
@@ -65,7 +63,6 @@ public class SmartReplyView extends ViewGroup {
private final SmartReplyConstants mConstants;
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final NotificationRemoteInputManager mRemoteInputManager;
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
/**
* The upper bound for the height of this view in pixels. Notifications are automatically
@@ -311,8 +308,7 @@ public class SmartReplyView extends ViewGroup {
() -> {
smartReplyController.smartActionClicked(
entry, actionIndex, action, smartActions.fromAssistant);
- postOnUiThread(() ->
- headsUpManager.removeNotification(entry.key, true));
+ headsUpManager.removeNotification(entry.key, true);
}));
// TODO(b/119010281): handle accessibility
@@ -323,10 +319,6 @@ public class SmartReplyView extends ViewGroup {
return button;
}
- private void postOnUiThread(Runnable runnable) {
- mMainThreadHandler.post(runnable);
- }
-
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(mContext, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 59aa52242f88..faebf60dc688 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,6 +26,7 @@ import android.view.View;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -112,6 +113,11 @@ public class InjectionInflationController {
* Creates the QSFooterImpl.
*/
QSFooterImpl createQsFooter();
+
+ /**
+ * Creates the NotificationStackScrollLayout.
+ */
+ NotificationStackScrollLayout createNotificationStackScrollLayout();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 490cdd5ce9bd..6b4f7edd54fe 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -69,10 +69,13 @@ public class Utils {
/**
* Sets visibility of this {@link View} given the states passed from
- * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int)}.
+ * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int, int)}.
*/
@Override
- public void disable(int state1, int state2, boolean animate) {
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != mView.getDisplay().getDisplayId()) {
+ return;
+ }
final boolean disabled = ((state1 & mMask1) != 0) || ((state2 & mMask2) != 0);
if (disabled == mDisabled) return;
mDisabled = disabled;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 3426e117ab13..61bfa758ad79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -69,4 +69,10 @@ public class DependencyTest extends SysuiTestCase {
mDependency.onConfigurationChanged(null);
verify(d).onConfigurationChanged(eq(null));
}
+
+ @Test
+ public void testInitDependency() {
+ Dependency.clearDependencies();
+ Dependency.initDependencies(mContext);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index f278a17d0637..f8912bcca302 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
@@ -35,197 +36,95 @@ import android.support.test.runner.AndroidJUnit4;
import android.widget.RemoteViews;
import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ForegroundServiceControllerTest extends SysuiTestCase {
- public static @UserIdInt int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
- public static @UserIdInt int USERID_TWO = USERID_ONE + 1;
+ @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
+ @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
- private ForegroundServiceController fsc;
+ private ForegroundServiceController mFsc;
+ private ForegroundServiceNotificationListener mListener;
+ private NotificationEntryListener mEntryListener;
@Before
public void setUp() throws Exception {
- fsc = new ForegroundServiceControllerImpl(mContext);
- }
-
- @Test
- public void testNotificationCRUD_dungeon() {
- StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1");
- StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2");
- StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3");
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
-
- // these are never added to the tracker
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
- // should still not be there
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-
- assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
- assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
- }
-
- @Test
- public void testNotificationCRUD_stdLayout() {
- StatusBarNotification sbn_user1_app1_fg =
- makeMockFgSBN(USERID_ONE, "com.example.app1", 0, true);
- StatusBarNotification sbn_user2_app2_fg =
- makeMockFgSBN(USERID_TWO, "com.example.app2", 1, true);
- StatusBarNotification sbn_user1_app3_fg =
- makeMockFgSBN(USERID_ONE, "com.example.app3", 2, true);
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
-
- // these are never added to the tracker
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
- // should still not be there
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
-
- fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-
- assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
- assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
- assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.removeNotification(sbn_user2_app1));
+ mFsc = new ForegroundServiceController();
+ NotificationEntryManager notificationEntryManager = mock(NotificationEntryManager.class);
+ mListener = new ForegroundServiceNotificationListener(
+ mContext, mFsc, notificationEntryManager);
+ ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
+ ArgumentCaptor.forClass(NotificationEntryListener.class);
+ verify(notificationEntryManager).addNotificationEntryListener(
+ entryListenerCaptor.capture());
+ mEntryListener = entryListenerCaptor.getValue();
}
@Test
public void testAppOpsCRUD() {
// no crash on remove that doesn't exist
- fsc.onAppOpChanged(9, 1000, "pkg1", false);
- assertNull(fsc.getAppOps(0, "pkg1"));
+ mFsc.onAppOpChanged(9, 1000, "pkg1", false);
+ assertNull(mFsc.getAppOps(0, "pkg1"));
// multiuser & multipackage
- fsc.onAppOpChanged(8, 50, "pkg1", true);
- fsc.onAppOpChanged(1, 60, "pkg3", true);
- fsc.onAppOpChanged(7, 500000, "pkg2", true);
+ mFsc.onAppOpChanged(8, 50, "pkg1", true);
+ mFsc.onAppOpChanged(1, 60, "pkg3", true);
+ mFsc.onAppOpChanged(7, 500000, "pkg2", true);
- assertEquals(1, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+ assertEquals(1, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
- assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
- assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+ assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
- assertEquals(1, fsc.getAppOps(0, "pkg3").size());
- assertTrue(fsc.getAppOps(0, "pkg3").contains(1));
+ assertEquals(1, mFsc.getAppOps(0, "pkg3").size());
+ assertTrue(mFsc.getAppOps(0, "pkg3").contains(1));
// multiple ops for the same package
- fsc.onAppOpChanged(9, 50, "pkg1", true);
- fsc.onAppOpChanged(5, 50, "pkg1", true);
+ mFsc.onAppOpChanged(9, 50, "pkg1", true);
+ mFsc.onAppOpChanged(5, 50, "pkg1", true);
- assertEquals(3, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(9));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+ assertEquals(3, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(9));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
- assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
- assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+ assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+ assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
// remove one of the multiples
- fsc.onAppOpChanged(9, 50, "pkg1", false);
- assertEquals(2, fsc.getAppOps(0, "pkg1").size());
- assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
- assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+ mFsc.onAppOpChanged(9, 50, "pkg1", false);
+ assertEquals(2, mFsc.getAppOps(0, "pkg1").size());
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+ assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
// remove last op
- fsc.onAppOpChanged(1, 60, "pkg3", false);
- assertNull(fsc.getAppOps(0, "pkg3"));
+ mFsc.onAppOpChanged(1, 60, "pkg3", false);
+ assertNull(mFsc.getAppOps(0, "pkg3"));
}
@Test
- public void testDungeonPredicate() {
+ public void testDisclosurePredicate() {
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
+ StatusBarNotification sbn_user1_disclosure = makeMockSBN(USERID_ONE, "android",
SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
null, Notification.FLAG_NO_CLEAR);
- assertTrue(fsc.isDungeonNotification(sbn_user1_dungeon));
- assertFalse(fsc.isDungeonNotification(sbn_user1_app1));
+ assertTrue(mFsc.isDisclosureNotification(sbn_user1_disclosure));
+ assertFalse(mFsc.isDisclosureNotification(sbn_user1_app1));
}
@Test
- public void testDungeonCRUD() {
- StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
- 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
- SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
- null, Notification.FLAG_NO_CLEAR);
-
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- fsc.addNotification(sbn_user1_dungeon, NotificationManager.IMPORTANCE_DEFAULT);
-
- fsc.removeNotification(sbn_user1_dungeon);
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- }
-
- @Test
- public void testNeedsDungeonAfterRemovingUnrelatedNotification() {
+ public void testNeedsDisclosureAfterRemovingUnrelatedNotification() {
final String PKG1 = "com.example.app100";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
@@ -233,21 +132,21 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
// first add a normal notification
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// nothing required yet
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// now the app starts a fg service
- fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
// add the fg notification
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
// remove the boring notification
- fsc.removeNotification(sbn_user1_app1);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has STILL got it covered
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has STILL got it covered
+ entryRemoved(sbn_user1_app1_fg);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
}
@Test
@@ -257,115 +156,117 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
// no services are "running"
- fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// switch to different package
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.updateNotification(makeMockDungeon(USERID_TWO, new String[]{PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_TWO, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO)); // finally user2 needs one too
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO)); // finally user2 needs one too
- fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2, PKG1}),
+ entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2, PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.removeNotification(makeMockDungeon(USERID_ONE, null /*unused*/));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(makeMockDisclosure(USERID_ONE, null /*unused*/));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
- fsc.removeNotification(makeMockDungeon(USERID_TWO, null /*unused*/));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(makeMockDisclosure(USERID_TWO, null /*unused*/));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
- public void testDungeonBasic() {
+ public void testDisclosureBasic() {
final String PKG1 = "com.example.app0";
StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
- fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
+ entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's take out the other notification and see what happens.
- fsc.removeNotification(sbn_user1_app1);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(sbn_user1_app1);
+ assertFalse(
+ mFsc.isDisclosureNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryUpdated(sbn_user1_app1_fg_sneaky,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// ok, ok, we'll put it back
sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryRemoved(sbn_user1_app1_fg_sneaky);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
// now let's test an upgrade
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1,
+ entryUpdated(sbn_user1_app1,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
// remove it, make sure we're out of compliance again
- assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+ entryRemoved(sbn_user1_app1); // was fg, should return true
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
// importance upgrade
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg,
+ entryUpdated(sbn_user1_app1_fg,
NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
// finally, let's turn off the service
- fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+ entryAdded(makeMockDisclosure(USERID_ONE, null),
NotificationManager.IMPORTANCE_DEFAULT);
- assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
- assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+ assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
}
@Test
@@ -375,8 +276,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
StatusBarNotification sbn_user1_overlay = makeMockSBN(USERID_ONE, "android",
0, "AlertWindowNotification", Notification.FLAG_NO_CLEAR);
- assertTrue(fsc.isSystemAlertNotification(sbn_user1_overlay));
- assertFalse(fsc.isSystemAlertNotification(sbn_user1_app1));
+ assertTrue(mFsc.isSystemAlertNotification(sbn_user1_overlay));
+ assertFalse(mFsc.isSystemAlertNotification(sbn_user1_app1));
}
@Test
@@ -386,54 +287,54 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true);
sbn_user1_app1.getNotification().flags = 0;
StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
// let's take out the non-fg notification and see what happens.
- fsc.removeNotification(sbn_user1_app1);
+ entryRemoved(sbn_user1_app1);
// still covered by sbn_user1_app1_fg
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
// let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
// ok, ok, we'll put it back
sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
+ entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
- assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
+ entryRemoved(sbn_user1_app1_fg_sneaky);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
// let's try a custom layout
sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false);
- fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+ entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
// now let's test an upgrade (non fg to fg)
- fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
+ entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
- fsc.updateNotification(sbn_user1_app1,
+ entryUpdated(sbn_user1_app1,
NotificationManager.IMPORTANCE_MIN); // this is now a fg notification
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
// remove it, make sure we're out of compliance again
- assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
- assertFalse(fsc.removeNotification(sbn_user1_app1));
- assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
- assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+ entryRemoved(sbn_user1_app1); // was fg, should return true
+ entryRemoved(sbn_user1_app1);
+ assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+ assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
}
private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
@@ -475,7 +376,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
}
- private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) {
+ private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
final Notification n = mock(Notification.class);
n.flags = Notification.FLAG_ONGOING_EVENT;
final Bundle extras = new Bundle();
@@ -488,4 +389,21 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
sbn.getNotification().extras = extras;
return sbn;
}
+
+ private void entryRemoved(StatusBarNotification notification) {
+ mEntryListener.onEntryRemoved(new NotificationData.Entry(notification),
+ null, false);
+ }
+
+ private void entryAdded(StatusBarNotification notification, int importance) {
+ NotificationData.Entry entry = new NotificationData.Entry(notification);
+ entry.importance = importance;
+ mEntryListener.onPendingEntryAdded(entry);
+ }
+
+ private void entryUpdated(StatusBarNotification notification, int importance) {
+ NotificationData.Entry entry = new NotificationData.Entry(notification);
+ entry.importance = importance;
+ mEntryListener.onEntryUpdated(entry);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index b84f85bdbc4c..e91a7e9bfcb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -16,13 +16,13 @@ package com.android.systemui;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
-import static com.android.systemui.ScreenDecorations.rectsToRegion;
+import static com.android.systemui.ScreenDecorations.rectsToRegion;
import static com.android.systemui.tuner.TunablePadding.FLAG_END;
import static com.android.systemui.tuner.TunablePadding.FLAG_START;
import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -87,7 +87,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
mWindowManager = mock(WindowManager.class);
mView = spy(new StatusBarWindowView(mContext, null));
when(mStatusBar.getStatusBarWindow()).thenReturn(mView);
- when(mStatusBar.getNavigationBarWindow()).thenReturn(mView);
mContext.putComponent(StatusBar.class, mStatusBar);
Display display = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
@@ -135,9 +134,12 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_NoCutout() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_bottom, 0);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 0);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_top, 0);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
@@ -154,7 +156,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 20);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 20);
@@ -174,7 +177,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testCutout() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
@@ -187,7 +191,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testDelayedCutout() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 0);
mContext.getOrCreateTestableResources()
.addOverride(dimen.rounded_corner_content_padding, 0);
@@ -235,12 +240,14 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testUpdateRoundedCorners() {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 20);
mScreenDecorations.start();
assertEquals(mScreenDecorations.mRoundedDefault, 20);
- mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 5);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, 5);
mScreenDecorations.onConfigurationChanged(null);
assertEquals(mScreenDecorations.mRoundedDefault, 5);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 8f2b2d065f72..31df4a3fc766 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -18,6 +18,10 @@ package com.android.systemui.bubbles;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.content.Context;
@@ -29,6 +33,9 @@ import android.widget.FrameLayout;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -36,6 +43,8 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -45,6 +54,8 @@ import org.mockito.MockitoAnnotations;
public class BubbleControllerTest extends SysuiTestCase {
@Mock
+ private NotificationEntryManager mNotificationEntryManager;
+ @Mock
private WindowManager mWindowManager;
@Mock
private IActivityManager mActivityManager;
@@ -52,17 +63,23 @@ public class BubbleControllerTest extends SysuiTestCase {
private DozeParameters mDozeParameters;
@Mock
private FrameLayout mStatusBarView;
+ @Captor
+ private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
private TestableBubbleController mBubbleController;
private StatusBarWindowController mStatusBarWindowController;
+ private NotificationEntryListener mEntryListener;
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mRow;
private ExpandableNotificationRow mRow2;
+ private final NotificationData mNotificationData = new NotificationData();
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
// Bubbles get added to status bar window view
mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
@@ -74,7 +91,15 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow = mNotificationTestHelper.createBubble();
mRow2 = mNotificationTestHelper.createBubble();
+ // Return non-null notification data from the NEM
+ when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
+
mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController);
+
+ // Get a reference to the BubbleController's entry listener
+ verify(mNotificationEntryManager, atLeastOnce())
+ .addNotificationEntryListener(mEntryListenerCaptor.capture());
+ mEntryListener = mEntryListenerCaptor.getValue();
}
@Test
@@ -102,6 +127,8 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(mRow.getEntry().key);
assertFalse(mStatusBarWindowController.getBubblesShowing());
+ assertTrue(mRow.getEntry().isBubbleDismissed());
+ verify(mNotificationEntryManager).updateNotifications();
}
@Test
@@ -112,6 +139,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.dismissStack();
assertFalse(mStatusBarWindowController.getBubblesShowing());
+ verify(mNotificationEntryManager, times(3)).updateNotifications();
}
@Test
@@ -140,6 +168,12 @@ public class BubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isStackExpanded());
}
+ @Test
+ public void testMarkNewNotificationAsBubble() {
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ assertTrue(mRow.getEntry().isBubble());
+ }
+
static class TestableBubbleController extends BubbleController {
TestableBubbleController(Context context,
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 9946317fab89..926ff69651be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -17,7 +17,9 @@
package com.android.systemui.doze;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -37,6 +39,7 @@ import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.doze.DozeMachine.State;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -66,6 +69,7 @@ public class DozeDockHandlerTest extends SysuiTestCase {
mMachine = mock(DozeMachine.class);
mHost = spy(new DozeHostFake());
mConfig = DozeConfigurationUtil.createMockConfig();
+ doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
mDockManagerFake = spy(new DockManagerFake());
mContext.putComponent(DockManager.class, mDockManagerFake);
@@ -75,7 +79,7 @@ public class DozeDockHandlerTest extends SysuiTestCase {
}
@Test
- public void testDockEventListener_registerAndUnregister() throws Exception {
+ public void testDockEventListener_registerAndUnregister() {
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
verify(mDockManagerFake).addListener(any());
@@ -86,55 +90,115 @@ public class DozeDockHandlerTest extends SysuiTestCase {
}
@Test
- public void testOnEvent_dockingWhenDoze_requestPulse() throws Exception {
+ public void testOnEvent_dockedWhenDoze_requestPulse() {
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
}
@Test
- public void testOnEvent_dockingWhenPausing_neverRequestPulse() throws Exception {
+ public void testOnEvent_dockedWhenDozeAoD_requestPulse() {
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD_PAUSING);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
- verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+ verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+ }
+
+ @Test
+ public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() {
+ mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ when(mMachine.getState()).thenReturn(State.DOZE_PULSING);
+ when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+
+ verify(mHost).stopPulsing();
}
@Test
- public void testOnEvent_undockedWhenPulsing_requestPulseOut() throws Exception {
+ public void testOnEvent_undockedWhenPulsing_requestPulseOut() {
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
- mDockManagerFake.setDockEvent(DockManager.STATE_UNDOCKING);
+ mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
verify(mHost).stopPulsing();
}
@Test
- public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() throws Exception {
+ public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() {
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
- mDockManagerFake.setDockEvent(DockManager.STATE_UNDOCKING);
+ mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
verify(mHost, never()).stopPulsing();
}
@Test
- public void testTransitionToDozeWhenDocking_RequestPulse() throws Exception {
+ public void testOnEvent_undockedWhenDozeAndEnabledAoD_requestDozeAoD() {
+ doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
- mDockManagerFake.setDockEvent(DockManager.STATE_DOCKING);
- mDockHandler.transitionTo(DozeMachine.State.DOZE_AOD_PAUSING, DozeMachine.State.DOZE);
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+ mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
+
+ verify(mMachine).requestState(eq(State.DOZE_AOD));
+ }
+
+ @Test
+ public void testTransitionToDoze_whenDocked_requestPulse() {
+ mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+ mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE);
+
TestableLooper.get(this).processAllMessages();
verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
}
+
+ @Test
+ public void testTransitionToDozeAoD_whenDocked_requestPulse() {
+ mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
+ mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE_AOD);
+
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+ }
+
+ @Test
+ public void testTransitionToDoze_whenDockedHide_neverRequestPulse() {
+ mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+ mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+
+ verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+ }
+
+ @Test
+ public void testTransitionToDozeAoD_whenDockedHide_requestDoze() {
+ mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
+ mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
+
+ mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_AOD);
+
+ verify(mMachine).requestState(eq(State.DOZE));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 2cb326eb7269..823485f4624d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -39,6 +39,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -92,7 +93,8 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
processAllMessages();
QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
- mock(PluginManager.class), mock(TunerService.class));
+ mock(PluginManager.class), mock(TunerService.class),
+ () -> mock(AutoTileManager.class));
qs.setHost(host);
qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 63f4bbc73ed8..03278b4aadc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.tuner.TunerService;
@@ -65,7 +66,8 @@ public class TileServicesTest extends SysuiTestCase {
new Handler(),
Looper.myLooper(),
mock(PluginManager.class),
- mock(TunerService.class));
+ mock(TunerService.class),
+ () -> mock(AutoTileManager.class));
mTileService = new TestTileServices(host, Looper.getMainLooper());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index a04e57bb4990..51d94f08000a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -16,6 +16,7 @@ package com.android.systemui.statusbar;
import static android.view.Display.DEFAULT_DISPLAY;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -42,10 +43,10 @@ public class CommandQueueTest extends SysuiTestCase {
@Before
public void setup() {
- mCommandQueue = new CommandQueue();
+ mCommandQueue = new CommandQueue(mContext);
mCallbacks = mock(Callbacks.class);
mCommandQueue.addCallback(mCallbacks);
- verify(mCallbacks).disable(eq(0), eq(0), eq(false));
+ verify(mCallbacks).disable(anyInt(), eq(0), eq(0), eq(false));
}
@After
@@ -73,7 +74,7 @@ public class CommandQueueTest extends SysuiTestCase {
int state2 = 42;
mCommandQueue.disable(DEFAULT_DISPLAY, state1, state2);
waitForIdleSync();
- verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
+ verify(mCallbacks).disable(eq(DEFAULT_DISPLAY), eq(state1), eq(state2), eq(true));
}
@Test
@@ -104,7 +105,8 @@ public class CommandQueueTest extends SysuiTestCase {
Rect r = new Rect();
mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r);
waitForIdleSync();
- verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
+ verify(mCallbacks).setSystemUiVisibility(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+ eq(null), eq(r));
}
// TODO(b/117478341): add test case for multi-display
@@ -112,7 +114,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void testTopAppWindowChanged() {
mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
waitForIdleSync();
- verify(mCallbacks).topAppWindowChanged(eq(true));
+ verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
}
// TODO(b/117478341): add test case for multi-display
@@ -120,7 +122,8 @@ public class CommandQueueTest extends SysuiTestCase {
public void testShowImeButton() {
mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
+ verify(mCallbacks).setImeWindowStatus(
+ eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true));
}
@Test
@@ -177,7 +180,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void testSetWindowState() {
mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
waitForIdleSync();
- verify(mCallbacks).setWindowState(eq(1), eq(2));
+ verify(mCallbacks).setWindowState(eq(DEFAULT_DISPLAY), eq(1), eq(2));
}
@Test
@@ -192,7 +195,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void testAppTransitionPending() {
mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
waitForIdleSync();
- verify(mCallbacks).appTransitionPending(eq(false));
+ verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
}
// TODO(b/117478341): add test case for multi-display
@@ -200,7 +203,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void testAppTransitionCancelled() {
mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
waitForIdleSync();
- verify(mCallbacks).appTransitionCancelled();
+ verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
}
// TODO(b/117478341): add test case for multi-display
@@ -208,7 +211,8 @@ public class CommandQueueTest extends SysuiTestCase {
public void testAppTransitionStarting() {
mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
waitForIdleSync();
- verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false));
+ verify(mCallbacks).appTransitionStarting(
+ eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
}
// TODO(b/117478341): add test case for multi-display
@@ -216,7 +220,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void testAppTransitionFinished() {
mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
waitForIdleSync();
- verify(mCallbacks).appTransitionFinished();
+ verify(mCallbacks).appTransitionFinished(eq(DEFAULT_DISPLAY));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 8cf4b05b6371..e716421a1e69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -77,7 +77,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Mock private ShadeController mShadeController;
private NotificationViewHierarchyManager mViewHierarchyManager;
- private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);
+ private NotificationTestHelper mHelper;
@Before
public void setUp() {
@@ -90,6 +90,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
+ mHelper = new NotificationTestHelper(mContext);
+
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index cb02dc601c73..6197341acda5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -52,7 +52,6 @@ import android.util.ArraySet;
import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.InitController;
@@ -109,7 +108,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private HeadsUpManager mHeadsUpManager;
@Mock private NotificationListenerService.RankingMap mRankingMap;
@Mock private RemoteInputController mRemoteInputController;
- @Mock private IStatusBarService mBarService;
// Dependency mocks:
@Mock private ForegroundServiceController mForegroundServiceController;
@@ -123,6 +121,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private MetricsLogger mMetricsLogger;
@Mock private SmartReplyController mSmartReplyController;
@Mock private RowInflaterTask mAsyncInflationTask;
+ @Mock private NotificationRowBinder mMockedRowBinder;
private NotificationData.Entry mEntry;
private StatusBarNotification mSbn;
@@ -132,9 +131,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
private class TestableNotificationEntryManager extends NotificationEntryManager {
private final CountDownLatch mCountDownLatch;
- public TestableNotificationEntryManager(Context context, IStatusBarService barService) {
+ TestableNotificationEntryManager(Context context) {
super(context);
- mBarService = barService;
mCountDownLatch = new CountDownLatch(1);
}
@@ -227,7 +225,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry = new NotificationData.Entry(mSbn);
mEntry.expandedIcon = mock(StatusBarIconView.class);
- mEntryManager = new TestableNotificationEntryManager(mContext, mBarService);
+ mEntryManager = new TestableNotificationEntryManager(mContext);
Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -258,9 +256,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
// Check that no inflation error occurred.
- verify(mBarService, never()).onNotificationError(any(), any(), anyInt(), anyInt(), anyInt(),
- any(), anyInt());
- verify(mForegroundServiceController).addNotification(eq(mSbn), anyInt());
+ verify(mEntryListener, never()).onInflationError(any(), any());
// Row inflation:
ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
@@ -293,11 +289,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
// Wait for content update.
assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
- verify(mBarService, never()).onNotificationError(any(), any(), anyInt(), anyInt(), anyInt(),
- any(), anyInt());
+ verify(mEntryListener, never()).onInflationError(any(), any());
verify(mPresenter).updateNotificationViews();
- verify(mForegroundServiceController).updateNotification(eq(mSbn), anyInt());
verify(mEntryListener).onEntryUpdated(mEntry);
assertNotNull(mEntry.getRow());
assertEquals(mEntry.userSentiment,
@@ -313,14 +307,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
- verify(mBarService, never()).onNotificationError(any(), any(), anyInt(), anyInt(), anyInt(),
- any(), anyInt());
+ verify(mEntryListener, never()).onInflationError(any(), any());
- verify(mForegroundServiceController).removeNotification(mSbn);
verify(mListContainer).cleanUpViewStateForEntry(mEntry);
verify(mPresenter).updateNotificationViews();
- verify(mEntryListener).onEntryRemoved(mEntry, mSbn.getKey(), mSbn,
- false /* lifetimeExtended */, false /* removedByUser */);
+ verify(mEntryListener).onEntryRemoved(
+ mEntry, null, false /* removedByUser */);
verify(mRow).setRemoved();
assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
@@ -344,8 +336,31 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
verify(extender).setShouldManageLifetime(mEntry, true /* shouldManage */);
- verify(mEntryListener).onEntryRemoved(mEntry, mSbn.getKey(), null,
- true /* lifetimeExtended */, false /* removedByUser */);
+ verify(mEntryListener, never()).onEntryRemoved(
+ mEntry, null, false /* removedByUser */);
+ }
+
+ @Test
+ public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ mEntryManager.removeNotification("not_a_real_key", mRankingMap);
+
+ verify(mEntryListener, never()).onEntryRemoved(
+ mEntry, null, false /* removedByUser */);
+ }
+
+ @Test
+ public void testRemoveNotification_whilePending() throws InterruptedException {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ mEntryManager.setRowBinder(mMockedRowBinder);
+
+ mEntryManager.addNotification(mSbn, mRankingMap);
+ mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
+
+ verify(mEntryListener, never()).onEntryRemoved(
+ mEntry, null, false /* removedByUser */);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index caa3ca6cc63a..afdeb62a8f28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.Handler;
import android.os.Looper;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
@@ -41,9 +40,9 @@ import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -53,10 +52,11 @@ import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -67,7 +67,6 @@ public class NotificationLoggerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
- @Mock private NotificationPresenter mPresenter;
@Mock private NotificationListContainer mListContainer;
@Mock private IStatusBarService mBarService;
@Mock private NotificationData mNotificationData;
@@ -76,28 +75,32 @@ public class NotificationLoggerTest extends SysuiTestCase {
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationListener mListener;
+ @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
private NotificationData.Entry mEntry;
- private StatusBarNotification mSbn;
private TestableNotificationLogger mLogger;
+ private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
@Before
- public void setUp() throws RemoteException {
+ public void setUp() {
MockitoAnnotations.initMocks(this);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(NotificationListener.class, mListener);
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
- mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
+ StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
+ 0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
- mEntry = new NotificationData.Entry(mSbn);
+ mEntry = new NotificationData.Entry(sbn);
mEntry.setRow(mRow);
mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
mEntryManager, mock(StatusBarStateController.class), mBarService);
mLogger.setUpWithContainer(mListContainer);
+ verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+ mNotificationEntryListener = mEntryListenerCaptor.getValue();
}
@Test
@@ -106,7 +109,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
NotificationVisibility.obtain(mEntry.key, 0, 1, true)
};
NotificationVisibility[] noLongerVisibleKeys = {};
- doAnswer((Answer) invocation -> {
+ doAnswer(invocation -> {
try {
assertArrayEquals(newlyVisibleKeys,
(NotificationVisibility[]) invocation.getArguments()[0]);
@@ -158,7 +161,7 @@ public class NotificationLoggerTest extends SysuiTestCase {
private class TestableNotificationLogger extends NotificationLogger {
- public TestableNotificationLogger(NotificationListener notificationListener,
+ TestableNotificationLogger(NotificationListener notificationListener,
UiOffloadThread uiOffloadThread,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
@@ -169,13 +172,9 @@ public class NotificationLoggerTest extends SysuiTestCase {
mHandler = Handler.createAsync(Looper.myLooper());
}
- public OnChildLocationsChangedListener
+ OnChildLocationsChangedListener
getChildLocationsChangedListenerForTest() {
return mNotificationLocationsChangedListener;
}
-
- public Handler getHandlerForTest() {
- return mHandler;
- }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index f0fa7887a0f9..82b42c51622d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -159,28 +159,37 @@ public class NotificationContentViewTest extends SysuiTestCase {
verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
}
- private void setupAppGeneratedReplies(CharSequence[] smartReplyTitles) {
- Notification.Action freeFormAction =
- new Notification.Action.Builder(null, "Freeform Test Action", null).build();
- setupAppGeneratedReplies(smartReplyTitles, freeFormAction);
+ private void setupAppGeneratedReplies(CharSequence[] smartReplies) {
+ setupAppGeneratedReplies(smartReplies, true /* allowSystemGeneratedReplies */);
}
private void setupAppGeneratedReplies(
- CharSequence[] smartReplyTitles,
- Notification.Action freeFormRemoteInputAction) {
+ CharSequence[] smartReplies, boolean allowSystemGeneratedReplies) {
PendingIntent pendingIntent =
PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0);
Notification.Action action =
new Notification.Action.Builder(null, "Test Action", pendingIntent).build();
- when(mRemoteInput.getChoices()).thenReturn(smartReplyTitles);
+ when(mRemoteInput.getChoices()).thenReturn(smartReplies);
Pair<RemoteInput, Notification.Action> remoteInputActionPair =
Pair.create(mRemoteInput, action);
when(mNotification.findRemoteInputActionPair(false)).thenReturn(remoteInputActionPair);
+ Notification.Action freeFormRemoteInputAction =
+ createActionBuilder("Freeform Test Action")
+ .setAllowGeneratedReplies(allowSystemGeneratedReplies)
+ .build();
Pair<RemoteInput, Notification.Action> freeFormRemoteInputActionPair =
Pair.create(mFreeFormRemoteInput, freeFormRemoteInputAction);
when(mNotification.findRemoteInputActionPair(true)).thenReturn(
freeFormRemoteInputActionPair);
+
+ when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
+ }
+
+ private void setupAppGeneratedSuggestions(
+ CharSequence[] smartReplies, List<Notification.Action> smartActions) {
+ setupAppGeneratedReplies(smartReplies);
+ when(mNotification.getContextualActions()).thenReturn(smartActions);
}
@Test
@@ -198,7 +207,6 @@ public class NotificationContentViewTest extends SysuiTestCase {
public void chooseSmartRepliesAndActions_appGeneratedSmartReplies() {
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
setupAppGeneratedReplies(smartReplies);
- when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
NotificationContentView.SmartRepliesAndActions repliesAndActions =
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
@@ -211,12 +219,9 @@ public class NotificationContentViewTest extends SysuiTestCase {
@Test
public void chooseSmartRepliesAndActions_appGeneratedSmartRepliesAndActions() {
CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
- setupAppGeneratedReplies(smartReplies);
- when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
-
List<Notification.Action> smartActions =
createActions(new String[] {"Test Action 1", "Test Action 2"});
- when(mNotification.getContextualActions()).thenReturn(smartActions);
+ setupAppGeneratedSuggestions(smartReplies, smartActions);
NotificationContentView.SmartRepliesAndActions repliesAndActions =
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
@@ -229,15 +234,11 @@ public class NotificationContentViewTest extends SysuiTestCase {
@Test
public void chooseSmartRepliesAndActions_sysGeneratedSmartReplies() {
- Notification.Action freeFormAction = createActionBuilder("Freeform Action")
- .setAllowGeneratedReplies(true)
- .build();
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
// replies.
- setupAppGeneratedReplies(null, freeFormAction);
+ setupAppGeneratedReplies(null /* smartReplies */);
- mEntry.smartReplies =
- new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
+ mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
NotificationContentView.SmartRepliesAndActions repliesAndActions =
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
@@ -248,12 +249,9 @@ public class NotificationContentViewTest extends SysuiTestCase {
@Test
public void chooseSmartRepliesAndActions_noSysGeneratedSmartRepliesIfNotAllowed() {
- Notification.Action freeFormAction = createActionBuilder("Freeform Action")
- .setAllowGeneratedReplies(false)
- .build();
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
// replies.
- setupAppGeneratedReplies(null, freeFormAction);
+ setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
mEntry.smartReplies =
new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
@@ -268,7 +266,7 @@ public class NotificationContentViewTest extends SysuiTestCase {
public void chooseSmartRepliesAndActions_sysGeneratedSmartActions() {
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
// actions.
- setupAppGeneratedReplies(null);
+ setupAppGeneratedReplies(null /* smartReplies */);
mEntry.systemGeneratedSmartActions =
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
@@ -283,18 +281,12 @@ public class NotificationContentViewTest extends SysuiTestCase {
@Test
public void chooseSmartRepliesAndActions_appGenPreferredOverSysGen() {
- Notification.Action freeFormAction = createActionBuilder("Freeform Action")
- .setAllowGeneratedReplies(true)
- .build();
CharSequence[] appGenSmartReplies = new String[] {"Reply1", "Reply2"};
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
// replies.
- setupAppGeneratedReplies(appGenSmartReplies, freeFormAction);
- when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
-
List<Notification.Action> appGenSmartActions =
createActions(new String[] {"Test Action 1", "Test Action 2"});
- when(mNotification.getContextualActions()).thenReturn(appGenSmartActions);
+ setupAppGeneratedSuggestions(appGenSmartReplies, appGenSmartActions);
mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
mEntry.systemGeneratedSmartActions =
@@ -313,12 +305,12 @@ public class NotificationContentViewTest extends SysuiTestCase {
public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
// Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
// actions.
- setupAppGeneratedReplies(null);
-
+ setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);
-
+ mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
mEntry.systemGeneratedSmartActions =
createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
+
NotificationContentView.SmartRepliesAndActions repliesAndActions =
NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index d28f0172e7e0..ecb0cf8ef902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -32,6 +32,7 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
@@ -44,6 +45,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
@@ -54,6 +56,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -69,6 +72,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -79,6 +83,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -177,6 +182,29 @@ public class NotificationInfoTest extends SysuiTestCase {
() -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility());
}
+ class ImportanceChangeLogMaker implements ArgumentMatcher<LogMaker> {
+ private static final int CATEGORY = MetricsProto.MetricsEvent.ACTION_SAVE_IMPORTANCE;
+ private int mType, mSubtype;
+
+ ImportanceChangeLogMaker(int type, int subtype) {
+ mType = type;
+ mSubtype = subtype;
+ }
+ public boolean matches(LogMaker l) {
+ return (l.getCategory() == CATEGORY)
+ && (l.getType() == mType)
+ && (l.getSubtype() == mSubtype);
+ }
+
+ public String toString() {
+ return String.format("LogMaker(%d, %d, %d)", CATEGORY, mType, mSubtype);
+ }
+ }
+
+ private LogMaker importanceChangeLog(int type, int subtype) {
+ return argThat(new ImportanceChangeLogMaker(type, subtype));
+ }
+
@Test
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -475,7 +503,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
- verify(mMetricsLogger, times(0)).count(anyString(), anyInt());
+ verifyZeroInteractions(mMetricsLogger);
}
@Test
@@ -484,7 +512,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
true, true, IMPORTANCE_DEFAULT);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
- verify(mMetricsLogger, times(1)).count(anyString(), anyInt());
+ verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
}
@Test
@@ -827,6 +855,9 @@ public class NotificationInfoTest extends SysuiTestCase {
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
+ verify(mMetricsLogger).write(importanceChangeLog(
+ MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW));
+
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
@@ -860,6 +891,9 @@ public class NotificationInfoTest extends SysuiTestCase {
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
+ verify(mMetricsLogger).write(importanceChangeLog(
+ MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW));
+
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
@@ -936,15 +970,14 @@ public class NotificationInfoTest extends SysuiTestCase {
waitForUndoButton();
mNotificationInfo.findViewById(R.id.undo).performClick();
waitForStopButton();
- mNotificationInfo.handleCloseControls(true, false);
+ // mNotificationInfo.handleCloseControls doesn't get called by this interaction.
+
+ verify(mMetricsLogger).write(importanceChangeLog(
+ MetricsProto.MetricsEvent.TYPE_DISMISS, IMPORTANCE_NONE - IMPORTANCE_LOW));
mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
- assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+ verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -958,15 +991,11 @@ public class NotificationInfoTest extends SysuiTestCase {
waitForUndoButton();
mNotificationInfo.findViewById(R.id.undo).performClick();
waitForStopButton();
- mNotificationInfo.handleCloseControls(true, false);
+ // mNotificationInfo.handleCloseControls doesn't get called by this code path
mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
- assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+ verify(mMockINotificationManager, times(0)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index b8c7ee093ecc..b66d0ab78fd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -35,12 +35,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Looper;
-import android.os.PowerManager;
import android.provider.Settings;
-import android.service.dreams.IDreamManager;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -104,8 +99,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationData mNotificationData;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
- @Mock private IDreamManager mDreamManager;
- private PowerManager mPowerManager;
private TestableNotificationEntryManager mEntryManager;
private int mOriginalInterruptionModelSetting;
@@ -122,12 +115,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
- IPowerManager powerManagerService = mock(IPowerManager.class);
- mPowerManager = new PowerManager(mContext, powerManagerService,
- Handler.createAsync(Looper.myLooper()));
-
- mEntryManager = new TestableNotificationEntryManager(mPowerManager,
- mContext);
+ mEntryManager = new TestableNotificationEntryManager(mContext);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager,
@@ -135,7 +123,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
NotificationShelf notificationShelf = mock(NotificationShelf.class);
- mStackScroller = spy(new NotificationStackScrollLayout(getContext()));
+ mStackScroller = spy(new NotificationStackScrollLayout(getContext(), null,
+ true /* allowLongPress */));
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
mStackScroller.setScrimController(mock(ScrimController.class));
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 1481aef6c2f4..c0f7f0ce217f 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.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -30,6 +31,8 @@ import com.android.internal.app.ColorDisplayController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +54,11 @@ public class AutoTileManagerTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
- Handler.createAsync(TestableLooper.get(this).getLooper()));
+ Handler.createAsync(TestableLooper.get(this).getLooper()),
+ mock(HotspotController.class),
+ mock(DataSaverController.class),
+ mock(ManagedProfileController.class),
+ mock(ColorDisplayController.class));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index d99e46d6de12..add8838362be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeast;
@@ -74,7 +76,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
fragment.initNotificationIconArea(mMockNotificiationAreaController);
- fragment.disable(0, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
@@ -89,12 +91,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
fragment.initNotificationIconArea(mMockNotificiationAreaController);
- fragment.disable(StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
- fragment.disable(0, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
@@ -107,11 +109,11 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
fragment.initNotificationIconArea(mMockNotificiationAreaController);
- fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
- fragment.disable(0, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
@@ -123,11 +125,11 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
fragment.initNotificationIconArea(mMockNotificiationAreaController);
- fragment.disable(StatusBarManager.DISABLE_CLOCK, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
- fragment.disable(0, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
}
@@ -139,7 +141,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
fragment.initNotificationIconArea(mMockNotificiationAreaController);
- fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 4f6329cb0c57..38d9ae7cfab4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -30,11 +30,11 @@ import android.view.View;
import android.widget.TextView;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import org.junit.Assert;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
index 76f57f049561..40d5415a9a47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
@@ -67,5 +67,4 @@ public class NavigationBarTransitionsTest extends SysuiTestCase {
assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT));
}
-
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 916232bf185a..79695fd6d38d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -237,7 +237,7 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
mGroupManager.onEntryAdded(summaryEntry);
mGroupManager.onEntryAdded(childEntry);
- mNotificationEntryListener.onEntryRemoved(childEntry, childEntry.key, null, false, false);
+ mNotificationEntryListener.onEntryRemoved(childEntry, null, false);
assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 72b0156d25f9..4f95bc515d0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -14,17 +14,14 @@
package com.android.systemui.statusbar.phone;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
-import static org.mockito.ArgumentMatchers.eq;
+
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import android.graphics.Rect;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -32,15 +29,15 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
+import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 4fabe7f8cfbb..2bbfd7d8bb8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -61,7 +63,7 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
public void setup() {
mMetricsLogger = new FakeMetricsLogger();
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
- mCommandQueue = new CommandQueue();
+ mCommandQueue = new CommandQueue(mContext);
mContext.putComponent(CommandQueue.class, mCommandQueue);
mDependency.injectTestDependency(ShadeController.class, mShadeController);
@@ -81,7 +83,8 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- mCommandQueue.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
+ mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
+ false /* animate */);
TestableLooper.get(this).processAllMessages();
assertFalse("The panel shouldn't allow heads up while disabled",
@@ -94,7 +97,8 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
UserHandle.of(0), null, 0);
NotificationData.Entry entry = new NotificationData.Entry(sbn);
- mCommandQueue.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
+ mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
+ false /* animate */);
TestableLooper.get(this).processAllMessages();
assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e80694c2e946..a45a5c4c3a0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.view.Display.DEFAULT_DISPLAY;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -82,6 +83,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -196,13 +198,14 @@ public class StatusBarTest extends SysuiTestCase {
mDreamManager);
mDependency.injectTestDependency(NotificationInterruptionStateProvider.class,
mNotificationInterruptionStateProvider);
+ mDependency.injectMockDependency(NavigationBarController.class);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
mMetricsLogger = new FakeMetricsLogger();
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
- mEntryManager = new TestableNotificationEntryManager(mPowerManager, mContext);
+ mEntryManager = new TestableNotificationEntryManager(mContext);
mNotificationLogger = new NotificationLogger(mNotificationListener,
Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController);
mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
@@ -245,7 +248,8 @@ public class StatusBarTest extends SysuiTestCase {
mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class),
mDozeScrimController, mock(NotificationShelf.class),
mLockscreenUserManager, mCommandQueue, mNotificationPresenter,
- mock(BubbleController.class));
+ mock(BubbleController.class), mock(NavigationBarController.class),
+ mock(AutoHideController.class));
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mContext.getComponents();
SystemUIFactory.getInstance().getRootComponent()
@@ -544,7 +548,7 @@ public class StatusBarTest extends SysuiTestCase {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
when(mCommandQueue.panelsEnabled()).thenReturn(false);
- mStatusBar.disable(StatusBarManager.DISABLE_NONE,
+ mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
verify(mNotificationPanelView).setQsExpansionEnabled(false);
mStatusBar.animateExpandNotificationsPanel();
@@ -553,7 +557,8 @@ public class StatusBarTest extends SysuiTestCase {
verify(mNotificationPanelView, never()).expand(anyBoolean());
when(mCommandQueue.panelsEnabled()).thenReturn(true);
- mStatusBar.disable(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE, false);
+ mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NONE, false);
verify(mNotificationPanelView).setQsExpansionEnabled(true);
mStatusBar.animateExpandNotificationsPanel();
verify(mNotificationPanelView).expandWithoutQs();
@@ -695,7 +700,9 @@ public class StatusBarTest extends SysuiTestCase {
NotificationLockscreenUserManager notificationLockscreenUserManager,
CommandQueue commandQueue,
NotificationPresenter notificationPresenter,
- BubbleController bubbleController) {
+ BubbleController bubbleController,
+ NavigationBarController navBarController,
+ AutoHideController autoHideController) {
mStatusBarKeyguardViewManager = man;
mUnlockMethodCache = unlock;
mKeyguardIndicationController = key;
@@ -726,6 +733,8 @@ public class StatusBarTest extends SysuiTestCase {
mPresenter = notificationPresenter;
mGestureWakeLock = mock(PowerManager.WakeLock.class);
mBubbleController = bubbleController;
+ mNavigationBarController = navBarController;
+ mAutoHideController = autoHideController;
}
private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
@@ -752,9 +761,8 @@ public class StatusBarTest extends SysuiTestCase {
public static class TestableNotificationEntryManager extends NotificationEntryManager {
- public TestableNotificationEntryManager(PowerManager powerManager, Context context) {
+ public TestableNotificationEntryManager(Context context) {
super(context);
- mPowerManager = powerManager;
}
public void setUpForTest(NotificationPresenter presenter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
index e3a41bead26c..8b8e3f195d40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -14,11 +14,11 @@
package com.android.systemui.statusbar.policy;
-import static com.google.common.truth.Truth.assertThat;
-
import static junit.framework.TestCase.assertTrue;
+
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -59,7 +59,7 @@ public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
assertFalse(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
- verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
}
@Test
@@ -67,7 +67,7 @@ public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
assertTrue(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
- verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
}
@Test
@@ -78,7 +78,7 @@ public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
c.orientation = Configuration.ORIENTATION_LANDSCAPE;
mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
assertTrue(mRemoteInputQuickSettingsDisabler.misLandscape);
- verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
}
@Test
@@ -89,7 +89,7 @@ public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
c.orientation = Configuration.ORIENTATION_PORTRAIT;
mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
assertFalse(mRemoteInputQuickSettingsDisabler.misLandscape);
- verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+ verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
}
}
diff --git a/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
index baf09b11ac07..da1036159d34 100644
--- a/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Black accent color name application label. [CHAR LIMIT=50] -->
- <string name="accent_color_black_overlay" translatable="false">Black Accent Color</string>
+ <string name="accent_color_black_overlay" translatable="false">Black</string>
</resources>
diff --git a/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
index 4de344cbb65e..623a1dafb48d 100644
--- a/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Green accent color name application label. [CHAR LIMIT=50] -->
- <string name="accent_color_green_overlay" translatable="false">Green Accent Color</string>
+ <string name="accent_color_green_overlay" translatable="false">Green</string>
</resources>
diff --git a/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
index d1eb95a940ac..d1c71688979e 100644
--- a/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Purple accent color name application label. [CHAR LIMIT=50] -->
- <string name="accent_color_purple_overlay" translatable="false">Purple Accent Color</string>
+ <string name="accent_color_purple_overlay" translatable="false">Purple</string>
</resources>
diff --git a/packages/overlays/FontArbutusSourceOverlay/Android.mk b/packages/overlays/FontArbutusSourceOverlay/Android.mk
new file mode 100644
index 000000000000..23aee558257a
--- /dev/null
+++ b/packages/overlays/FontArbutusSourceOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := FontArbutusSource
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := FontArbutusSourceOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml b/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..46c06b969461
--- /dev/null
+++ b/packages/overlays/FontArbutusSourceOverlay/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.font.arbutussource"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="android.theme.customization.font"
+ android:priority="1"/>
+
+ <application android:label="@string/font_arbutus_source_overlay" android:hasCode="false">
+ <meta-data
+ android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS"
+ android:value="arbutus-slab,source-sans-pro,source-sans-pro-medium" />
+ </application>
+</manifest>
diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml
new file mode 100644
index 000000000000..165aab21c2e8
--- /dev/null
+++ b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of a font family to use for body text. -->
+ <string name="config_bodyFontFamily" translatable="false">source-sans-pro</string>
+ <!-- Name of a font family to use for medium body text. -->
+ <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-medium</string>
+ <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
+ <string name="config_headlineFontFamily" translatable="false">arbutus-slab</string>
+ <!-- Name of the font family used for system surfaces where the font should use medium weight -->
+ <string name="config_headlineFontFamilyMedium" translatable="false">arbutus-slab</string>
+</resources>
+
diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..d80eb20677c1
--- /dev/null
+++ b/packages/overlays/FontArbutusSourceOverlay/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Headline / Body font Arbutus Slab / Source Sans Pro overlay -->
+ <string name="font_arbutus_source_overlay" translatable="false">Arbutus Slab / Source Sans Pro</string>
+</resources>
diff --git a/packages/overlays/FontArvoLatoOverlay/Android.mk b/packages/overlays/FontArvoLatoOverlay/Android.mk
new file mode 100644
index 000000000000..3433ecfd1f6b
--- /dev/null
+++ b/packages/overlays/FontArvoLatoOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := FontArvoLato
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := FontArvoLatoOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml b/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..3f2e5de39c0b
--- /dev/null
+++ b/packages/overlays/FontArvoLatoOverlay/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.font.arvolato"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="android.theme.customization.font"
+ android:priority="1"/>
+
+ <application android:label="@string/font_arvo_lato_overlay" android:hasCode="false">
+ <meta-data
+ android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS"
+ android:value="arvo,arvo-medium,lato,lato-medium" />
+ </application>
+</manifest>
diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml
new file mode 100644
index 000000000000..229c578b22da
--- /dev/null
+++ b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of a font family to use for body text. -->
+ <string name="config_bodyFontFamily" translatable="false">lato</string>
+ <!-- Name of a font family to use for medium body text. -->
+ <string name="config_bodyFontFamilyMedium" translatable="false">lato-medium</string>
+ <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
+ <string name="config_headlineFontFamily" translatable="false">arvo</string>
+ <!-- Name of the font family used for system surfaces where the font should use medium weight -->
+ <string name="config_headlineFontFamilyMedium" translatable="false">arvo-medium</string>
+</resources>
+
diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml b/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..9ea097f1fe48
--- /dev/null
+++ b/packages/overlays/FontArvoLatoOverlay/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Headline / Body font Arvo / Lato overlay -->
+ <string name="font_arvo_lato_overlay" translatable="false">Arvo / Lato</string>
+</resources>
diff --git a/packages/overlays/FontRubikRubikOverlay/Android.mk b/packages/overlays/FontRubikRubikOverlay/Android.mk
new file mode 100644
index 000000000000..21d617ef2c72
--- /dev/null
+++ b/packages/overlays/FontRubikRubikOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := FontRubikRubik
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := FontRubikRubikOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml b/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..1f28d46f087a
--- /dev/null
+++ b/packages/overlays/FontRubikRubikOverlay/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.font.rubikrubik"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="android.theme.customization.font"
+ android:priority="1"/>
+
+ <application android:label="@string/font_rubik_rubik_overlay" android:hasCode="false">
+ <meta-data
+ android:name="android.theme.customization.REQUIRED_SYSTEM_FONTS"
+ android:value="rubik,rubik-medium" />
+ </application>
+</manifest>
diff --git a/packages/overlays/FontRubikRubikOverlay/res/values/config.xml b/packages/overlays/FontRubikRubikOverlay/res/values/config.xml
new file mode 100644
index 000000000000..4f90e292e2f4
--- /dev/null
+++ b/packages/overlays/FontRubikRubikOverlay/res/values/config.xml
@@ -0,0 +1,28 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of a font family to use for body text. -->
+ <string name="config_bodyFontFamily" translatable="false">rubik</string>
+ <!-- Name of a font family to use for medium body text. -->
+ <string name="config_bodyFontFamilyMedium" translatable="false">rubik-medium</string>
+ <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
+ <string name="config_headlineFontFamily" translatable="false">rubik</string>
+ <!-- Name of the font family used for system surfaces where the font should use medium weight -->
+ <string name="config_headlineFontFamilyMedium" translatable="false">rubik-medium</string>
+</resources>
+
diff --git a/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml b/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..4bac7da0aa73
--- /dev/null
+++ b/packages/overlays/FontRubikRubikOverlay/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Headline / Body font Rubik overlay -->
+ <string name="font_rubik_rubik_overlay" translatable="false">Rubik / Rubik</string>
+</resources>
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml b/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
index f024615190ab..138c283b9a24 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeRoundedRectOverlay/res/values/config.xml
@@ -18,7 +18,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
- <string name="config_icon_mask" translatable="false">"M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58, 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"</string>
+ <string name="config_icon_mask" translatable="false">"M50,0L88,0 C94.4,0 100,5.4 100 12 L100,88 C100,94.6 94.6 100 88 100 L12,100 C5.4,100 0,94.6 0,88 L0 12 C0 5.4 5.4 0 12 0 L50,0 Z"</string>
<!-- Flag indicating whether round icons should be parsed from the application manifest. -->
<bool name="config_useRoundIcon">false</bool>
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml b/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
index dc5c196c97aa..3c4c24db53ba 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Rounded corner rectangle overlay -->
- <string name="icon_shape_roundedrect_overlay" translatable="false">RoundedRectangle Icons</string>
+ <string name="icon_shape_roundedrect_overlay" translatable="false">Rounded Rectangle</string>
</resources>
diff --git a/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml b/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
index 4fd39ff26bae..577216582608 100644
--- a/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Square icon overlay -->
- <string name="icon_shape_square_overlay" translatable="false">Square Icons</string>
+ <string name="icon_shape_square_overlay" translatable="false">Square</string>
</resources>
diff --git a/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml b/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
index b7c001c68a30..028eccb8c5a3 100644
--- a/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Squircle icon shape overlay -->
- <string name="icon_shape_squircle_overlay" translatable="false">Square Icons</string>
+ <string name="icon_shape_squircle_overlay" translatable="false">Squircle</string>
</resources>
diff --git a/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml b/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
index 43ad04d69c73..818e696577e9 100644
--- a/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeTeardropOverlay/res/values/config.xml
@@ -18,7 +18,7 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
- <string name="config_icon_mask" translatable="false">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</string>
+ <string name="config_icon_mask" translatable="false">"M50,0 C77.6,0 100,22.4 100,50 L100,88 C100,94.6 94.6,100 88,100 L50,100 C22.4 100 0 77.6 0 50C0 22.4 22.4 0 50 0 Z"</string>
<!-- Flag indicating whether round icons should be parsed from the application manifest. -->
<bool name="config_useRoundIcon">false</bool>
diff --git a/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml b/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
index d946ee8f97f2..db9fa9819714 100644
--- a/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Teardrop icon overlay -->
- <string name="icon_shape_teardrop_overlay" translatable="false">Teardrop Icons</string>
+ <string name="icon_shape_teardrop_overlay" translatable="false">Teardrop</string>
</resources>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3180b479b520..3379b1b6d15a 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6730,6 +6730,11 @@ message MetricsEvent {
// OS: Q
ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
+ // OPEN: Settings > Developer Options > Game Update Packages
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_GUP_DASHBOARD = 1613;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/accessibility/TEST_MAPPING b/services/accessibility/TEST_MAPPING
index 320924c954f8..d90c3bd9b4c2 100644
--- a/services/accessibility/TEST_MAPPING
+++ b/services/accessibility/TEST_MAPPING
@@ -7,7 +7,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -18,7 +18,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -29,7 +29,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -40,7 +40,7 @@
"include-filter": "com.android.server.accessibility"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -51,7 +51,7 @@
"include-filter": "com.android.internal.accessibility"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
},
@@ -62,7 +62,7 @@
"include-filter": "android.view.accessibility"
},
{
- "exclude-annotation": "android.support.test.filters.FlakyTest"
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0e9b407372e0..0348f2bf1c2b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -64,9 +64,11 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.AutofillFieldClassificationService.Scores;
import android.service.autofill.AutofillService;
+import android.service.autofill.CompositeUserData;
import android.service.autofill.Dataset;
import android.service.autofill.FieldClassification;
import android.service.autofill.FieldClassification.Match;
+import android.service.autofill.FieldClassificationUserData;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
@@ -1237,11 +1239,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
+ // Merge UserData if necessary.
+ // Fields in packageUserData will override corresponding fields in genericUserData.
+ final UserData genericUserData = mService.getUserData();
final UserData packageUserData = lastResponse.getUserData();
-
- final UserData userData;
- if (packageUserData != null) {
- // Replace default userData
+ final FieldClassificationUserData userData;
+ if (packageUserData == null && genericUserData == null) {
+ userData = null;
+ } else if (packageUserData != null && genericUserData != null) {
+ userData = new CompositeUserData(genericUserData, packageUserData);
+ } else if (packageUserData != null) {
userData = packageUserData;
} else {
userData = mService.getUserData();
@@ -1396,7 +1403,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@NonNull ArrayList<String> changedDatasetIds,
@NonNull ArrayList<AutofillId> manuallyFilledFieldIds,
@NonNull ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @NonNull UserData userData, @NonNull Collection<ViewState> viewStates) {
+ @NonNull FieldClassificationUserData userData,
+ @NonNull Collection<ViewState> viewStates) {
final String[] userValues = userData.getValues();
final String[] categoryIds = userData.getCategoryIds();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 704974417f87..6bd399042b29 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -36,7 +36,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.Environment;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -50,11 +49,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Set;
@@ -72,10 +67,6 @@ public class BackupManagerService {
public static final boolean MORE_DEBUG = false;
public static final boolean DEBUG_SCHEDULING = true;
- // File containing backup-enabled state. Contains a single byte to denote enabled status.
- // Nonzero is enabled; file missing or a zero byte is disabled.
- private static final String BACKUP_ENABLE_FILE = "backup_enabled";
-
// The published binder is a singleton Trampoline object that calls through to the proper code.
// This indirection lets us turn down the heavy implementation object on the fly without
// disturbing binders that have been cached elsewhere in the system.
@@ -136,7 +127,7 @@ public class BackupManagerService {
protected void startServiceForUser(int userId) {
UserBackupManagerService userBackupManagerService =
UserBackupManagerService.createAndInitializeService(
- userId, mContext, mTrampoline, mBackupThread, mTransportWhitelist);
+ userId, mContext, mTrampoline, mTransportWhitelist);
startServiceForUser(userId, userBackupManagerService);
}
@@ -150,7 +141,8 @@ public class BackupManagerService {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
try {
// TODO(b/121198604): Make enable file per-user and clean up indirection.
- mTrampoline.setBackupEnabledForUser(userId, readBackupEnableState(userId));
+ mTrampoline.setBackupEnabledForUser(
+ userId, UserBackupManagerFilePersistedSettings.readBackupEnableState(userId));
} catch (RemoteException e) {
// Can't happen, it's a local object.
}
@@ -160,7 +152,11 @@ public class BackupManagerService {
/** Stops the backup service for user {@code userId} when the user is stopped. */
@VisibleForTesting
protected void stopServiceForUser(int userId) {
- mServiceUsers.remove(userId);
+ UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId);
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.tearDownService();
+ }
}
SparseArray<UserBackupManagerService> getServiceUsers() {
@@ -773,44 +769,6 @@ public class BackupManagerService {
}
}
- private static boolean readBackupEnableState(int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- if (enableFile.exists()) {
- try (FileInputStream fin = new FileInputStream(enableFile)) {
- int state = fin.read();
- return state != 0;
- } catch (IOException e) {
- // can't read the file; fall through to assume disabled
- Slog.e(TAG, "Cannot read enable state; assuming disabled");
- }
- } else {
- if (DEBUG) {
- Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
- }
- }
- return false;
- }
-
- static void writeBackupEnableState(boolean enable, int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- File stage = new File(base, BACKUP_ENABLE_FILE + "-stage");
- try (FileOutputStream fout = new FileOutputStream(stage)) {
- fout.write(enable ? 1 : 0);
- fout.close();
- stage.renameTo(enableFile);
- // will be synced immediately by the try-with-resources call to close()
- } catch (IOException | RuntimeException e) {
- Slog.e(
- TAG,
- "Unable to record backup enable state; reverting to disabled: "
- + e.getMessage());
- enableFile.delete();
- stage.delete();
- }
- }
-
/** Implementation to receive lifecycle event callbacks for system services. */
public static final class Lifecycle extends SystemService {
public Lifecycle(Context context) {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java
new file mode 100644
index 000000000000..6a1de6378a5e
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import static com.android.server.backup.BackupManagerService.DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/** User settings which are persisted across reboots. */
+final class UserBackupManagerFilePersistedSettings {
+ // File containing backup-enabled state. Contains a single byte to denote enabled status.
+ // Nonzero is enabled; file missing or a zero byte is disabled.
+ private static final String BACKUP_ENABLE_FILE = "backup_enabled";
+
+ static boolean readBackupEnableState(int userId) {
+ return readBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId));
+ }
+
+ static void writeBackupEnableState(int userId, boolean enable) {
+ writeBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId), enable);
+ }
+
+ private static boolean readBackupEnableState(File baseDir) {
+ File enableFile = new File(baseDir, BACKUP_ENABLE_FILE);
+ if (enableFile.exists()) {
+ try (FileInputStream fin = new FileInputStream(enableFile)) {
+ int state = fin.read();
+ return state != 0;
+ } catch (IOException e) {
+ // can't read the file; fall through to assume disabled
+ Slog.e(TAG, "Cannot read enable state; assuming disabled");
+ }
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "isBackupEnabled() => false due to absent settings file");
+ }
+ }
+ return false;
+ }
+
+ private static void writeBackupEnableState(File baseDir, boolean enable) {
+ File enableFile = new File(baseDir, BACKUP_ENABLE_FILE);
+ File stage = new File(baseDir, BACKUP_ENABLE_FILE + "-stage");
+ try (FileOutputStream fout = new FileOutputStream(stage)) {
+ fout.write(enable ? 1 : 0);
+ fout.close();
+ stage.renameTo(enableFile);
+ // will be synced immediately by the try-with-resources call to close()
+ } catch (IOException | RuntimeException e) {
+ Slog.e(
+ TAG,
+ "Unable to record backup enable state; reverting to disabled: "
+ + e.getMessage());
+ enableFile.delete();
+ stage.delete();
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
new file mode 100644
index 000000000000..a0feaf9c8d15
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.os.Environment;
+
+import java.io.File;
+
+/** Directories used for user specific backup/restore persistent state and book-keeping. */
+public final class UserBackupManagerFiles {
+ // Name of the directories the service stores bookkeeping data under.
+ private static final String BACKUP_PERSISTENT_DIR = "backup";
+ private static final String BACKUP_STAGING_DIR = "backup_stage";
+
+ static File getBaseStateDir(int userId) {
+ // TODO (b/120424138) this should be per user
+ return new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+ }
+
+ static File getDataDir(int userId) {
+ // TODO (b/120424138) this should be per user
+ // This dir on /cache is managed directly in init.rc
+ return new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
+ }
+
+ /** Directory used by full backup engine to store state. */
+ public static File getFullBackupEngineFilesDir(int userId) {
+ // TODO (b/120424138) this should be per user
+ return new File("/data/system");
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2e414438c6ff..b669019ada76 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -70,7 +70,6 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -164,17 +163,9 @@ import java.util.concurrent.atomic.AtomicInteger;
/** System service that performs backup/restore operations. */
public class UserBackupManagerService {
- // File containing backup-enabled state. Contains a single byte;
- // nonzero == enabled. File missing or contains a zero byte == disabled.
- private static final String BACKUP_ENABLE_FILE = "backup_enabled";
-
// Persistently track the need to do a full init.
private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
- // Name of the directories the service stores bookkeeping data under.
- private static final String BACKUP_PERSISTENT_DIR = "backup";
- private static final String BACKUP_STAGING_DIR = "backup_stage";
-
// System-private key used for backing up an app's widget state. Must
// begin with U+FFxx by convention (we reserve all keys starting
// with U+FF00 or higher for system use).
@@ -254,6 +245,7 @@ public class UserBackupManagerService {
private final @UserIdInt int mUserId;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final TransportManager mTransportManager;
+ private final HandlerThread mUserBackupThread;
private Context mContext;
private PackageManager mPackageManager;
@@ -354,9 +346,9 @@ public class UserBackupManagerService {
final AtomicInteger mNextToken = new AtomicInteger();
// Where we keep our journal files and other bookkeeping.
- private File mBaseStateDir;
- private File mDataDir;
- private File mJournalDir;
+ private final File mBaseStateDir;
+ private final File mDataDir;
+ private final File mJournalDir;
@Nullable
private DataChangedJournal mJournal;
private File mFullBackupScheduleFile;
@@ -380,7 +372,6 @@ public class UserBackupManagerService {
@UserIdInt int userId,
Context context,
Trampoline trampoline,
- HandlerThread backupThread,
Set<ComponentName> transportWhitelist) {
String currentTransport =
Settings.Secure.getString(
@@ -395,13 +386,24 @@ public class UserBackupManagerService {
TransportManager transportManager =
new TransportManager(context, transportWhitelist, currentTransport);
- File baseStateDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+ File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId);
+ File dataDir = UserBackupManagerFiles.getDataDir(userId);
- // This dir on /cache is managed directly in init.rc
- File dataDir = new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
+ HandlerThread userBackupThread =
+ new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND);
+ userBackupThread.start();
+ if (DEBUG) {
+ Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId);
+ }
return createAndInitializeService(
- userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+ userId,
+ context,
+ trampoline,
+ userBackupThread,
+ baseStateDir,
+ dataDir,
+ transportManager);
}
/**
@@ -410,7 +412,7 @@ public class UserBackupManagerService {
* @param userId The user which this service is for.
* @param context The system server context.
* @param trampoline A reference to the proxy to {@link BackupManagerService}.
- * @param backupThread The thread running backup/restore operations for the user.
+ * @param userBackupThread The thread running backup/restore operations for the user.
* @param baseStateDir The directory we store the user's persistent bookkeeping data.
* @param dataDir The directory we store the user's temporary staging data.
* @param transportManager The {@link TransportManager} responsible for handling the user's
@@ -421,19 +423,25 @@ public class UserBackupManagerService {
@UserIdInt int userId,
Context context,
Trampoline trampoline,
- HandlerThread backupThread,
+ HandlerThread userBackupThread,
File baseStateDir,
File dataDir,
TransportManager transportManager) {
return new UserBackupManagerService(
- userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+ userId,
+ context,
+ trampoline,
+ userBackupThread,
+ baseStateDir,
+ dataDir,
+ transportManager);
}
private UserBackupManagerService(
@UserIdInt int userId,
Context context,
Trampoline parent,
- HandlerThread backupThread,
+ HandlerThread userBackupThread,
File baseStateDir,
File dataDir,
TransportManager transportManager) {
@@ -454,9 +462,9 @@ public class UserBackupManagerService {
BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
mAgentTimeoutParameters.start();
- // spin up the backup/restore handler thread
- checkNotNull(backupThread, "backupThread cannot be null");
- mBackupHandler = new BackupHandler(this, backupThread.getLooper());
+ checkNotNull(userBackupThread, "userBackupThread cannot be null");
+ mUserBackupThread = userBackupThread;
+ mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
// Set up our bookkeeping
final ContentResolver resolver = context.getContentResolver();
@@ -537,6 +545,11 @@ public class UserBackupManagerService {
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
}
+ /** Cleans up state when the user of this service is stopped. */
+ void tearDownService() {
+ mUserBackupThread.quit();
+ }
+
public BackupManagerConstants getConstants() {
return mConstants;
}
@@ -726,18 +739,10 @@ public class UserBackupManagerService {
return mBaseStateDir;
}
- public void setBaseStateDir(File baseStateDir) {
- mBaseStateDir = baseStateDir;
- }
-
public File getDataDir() {
return mDataDir;
}
- public void setDataDir(File dataDir) {
- mDataDir = dataDir;
- }
-
@Nullable
public DataChangedJournal getJournal() {
return mJournal;
@@ -2735,8 +2740,7 @@ public class UserBackupManagerService {
try {
boolean wasEnabled = mEnabled;
synchronized (this) {
- // TODO(b/118520567): Clean up writing backup enabled logic.
- BackupManagerService.writeBackupEnableState(enable, UserHandle.USER_SYSTEM);
+ UserBackupManagerFilePersistedSettings.writeBackupEnableState(mUserId, enable);
mEnabled = enable;
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 5e923393843e..45ca2af54b52 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -24,6 +24,7 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_METADATA
import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_WAIT;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
+import android.annotation.UserIdInt;
import android.app.ApplicationThreadConstants;
import android.app.IBackupAgent;
import android.app.backup.BackupTransport;
@@ -40,6 +41,7 @@ import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.backup.BackupAgentTimeoutParameters;
import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.UserBackupManagerFiles;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.utils.FullBackupUtils;
@@ -66,6 +68,7 @@ public class FullBackupEngine {
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
class FullBackupRunner implements Runnable {
+ private final @UserIdInt int mUserId;
private final PackageManager mPackageManager;
private final PackageInfo mPackage;
private final IBackupAgent mAgent;
@@ -81,13 +84,15 @@ public class FullBackupEngine {
int token,
boolean includeApks)
throws IOException {
+ // TODO: http://b/22388012
+ mUserId = UserHandle.USER_SYSTEM;
mPackageManager = backupManagerService.getPackageManager();
mPackage = packageInfo;
mAgent = agent;
mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
mToken = token;
mIncludeApks = includeApks;
- mFilesDir = new File("/data/system");
+ mFilesDir = UserBackupManagerFiles.getFullBackupEngineFilesDir(mUserId);
}
@Override
@@ -114,10 +119,8 @@ public class FullBackupEngine {
manifestFile.delete();
// Write widget data.
- // TODO: http://b/22388012
byte[] widgetData =
- AppWidgetBackupBridge.getWidgetState(
- packageName, UserHandle.USER_SYSTEM);
+ AppWidgetBackupBridge.getWidgetState(packageName, mUserId);
if (widgetData != null && widgetData.length > 0) {
File metadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
appMetadataBackupWriter.backupWidget(
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
new file mode 100644
index 000000000000..f27d37315ada
--- /dev/null
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Monitors the health of packages on the system and notifies interested observers when packages
+ * fail. All registered observers will be notified until an observer takes a mitigation action.
+ */
+public class PackageWatchdog {
+ private static final String TAG = "PackageWatchdog";
+ // Duration to count package failures before it resets to 0
+ private static final int TRIGGER_DURATION_MS = 60000;
+ // Number of package failures within the duration above before we notify observers
+ private static final int TRIGGER_FAILURE_COUNT = 5;
+ private static final int DB_VERSION = 1;
+ private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
+ private static final String TAG_PACKAGE = "package";
+ private static final String TAG_OBSERVER = "observer";
+ private static final String ATTR_VERSION = "version";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_DURATION = "duration";
+
+ private static PackageWatchdog sPackageWatchdog;
+
+ private final Object mLock = new Object();
+ // System server context
+ private final Context mContext;
+ // Handler to run package cleanup runnables
+ private final Handler mTimerHandler;
+ private final Handler mIoHandler;
+ // Contains (observer-name -> external-observer-handle) that have been registered during the
+ // current boot.
+ // It is populated when observers call #registerHealthObserver and it does not survive reboots.
+ @GuardedBy("mLock")
+ final ArrayMap<String, PackageHealthObserver> mRegisteredObservers = new ArrayMap<>();
+ // Contains (observer-name -> internal-observer-handle) that have ever been registered from
+ // previous boots. Observers with all packages expired are periodically pruned.
+ // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
+ @GuardedBy("mLock")
+ final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+ // File containing the XML data of monitored packages /data/system/package-watchdog.xml
+ private final AtomicFile mPolicyFile =
+ new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
+ "package-watchdog.xml"));
+ // Runnable to prune monitored packages that have expired
+ private final Runnable mPackageCleanup;
+ // Last SystemClock#uptimeMillis a package clean up was executed.
+ // 0 if mPackageCleanup not running.
+ private long mUptimeAtLastRescheduleMs;
+ // Duration a package cleanup was last scheduled for.
+ // 0 if mPackageCleanup not running.
+ private long mDurationAtLastReschedule;
+
+ private PackageWatchdog(Context context) {
+ mContext = context;
+ mTimerHandler = new Handler(Looper.myLooper());
+ mIoHandler = BackgroundThread.getHandler();
+ mPackageCleanup = this::rescheduleCleanup;
+ loadFromFile();
+ }
+
+ /** Creates or gets singleton instance of PackageWatchdog. */
+ public static PackageWatchdog getInstance(Context context) {
+ synchronized (PackageWatchdog.class) {
+ if (sPackageWatchdog == null) {
+ sPackageWatchdog = new PackageWatchdog(context);
+ }
+ return sPackageWatchdog;
+ }
+ }
+
+ /**
+ * Registers {@code observer} to listen for package failures
+ *
+ * <p>Observers are expected to call this on boot. It does not specify any packages but
+ * it will resume observing any packages requested from a previous boot.
+ */
+ public void registerHealthObserver(PackageHealthObserver observer) {
+ synchronized (mLock) {
+ mRegisteredObservers.put(observer.getName(), observer);
+ if (mDurationAtLastReschedule == 0) {
+ // Nothing running, schedule
+ rescheduleCleanup();
+ }
+ }
+ }
+
+ /**
+ * Starts observing the health of the {@code packages} for {@code observer} and notifies
+ * {@code observer} of any package failures within the monitoring duration.
+ *
+ * <p>If {@code observer} is already monitoring a package in {@code packageNames},
+ * the monitoring window of that package will be reset to {@code durationMs}.
+ *
+ * @throws IllegalArgumentException if {@code packageNames} is empty
+ * or {@code durationMs} is less than 1
+ */
+ public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
+ int durationMs) {
+ if (packageNames.isEmpty() || durationMs < 1) {
+ throw new IllegalArgumentException("Observation not started, no packages specified"
+ + "or invalid duration");
+ }
+ List<MonitoredPackage> packages = new ArrayList<>();
+ for (int i = 0; i < packageNames.size(); i++) {
+ packages.add(new MonitoredPackage(packageNames.get(i), durationMs));
+ }
+ synchronized (mLock) {
+ ObserverInternal oldObserver = mAllObservers.get(observer.getName());
+ if (oldObserver == null) {
+ Slog.d(TAG, observer.getName() + " started monitoring health of packages "
+ + packageNames);
+ mAllObservers.put(observer.getName(),
+ new ObserverInternal(observer.getName(), packages));
+ } else {
+ Slog.d(TAG, observer.getName() + " added the following packages to monitor "
+ + packageNames);
+ oldObserver.updatePackages(packages);
+ }
+ }
+ registerHealthObserver(observer);
+ // Always reschedule because we may need to expire packages
+ // earlier than we are already scheduled for
+ rescheduleCleanup();
+ saveToFileAsync();
+ }
+
+ /**
+ * Unregisters {@code observer} from listening to package failure.
+ * Additionally, this stops observing any packages that may have previously been observed
+ * even from a previous boot.
+ */
+ public void unregisterHealthObserver(PackageHealthObserver observer) {
+ synchronized (mLock) {
+ mAllObservers.remove(observer.getName());
+ mRegisteredObservers.remove(observer.getName());
+ }
+ saveToFileAsync();
+ }
+
+ // TODO(zezeozue:) Accept current versionCodes of failing packages?
+ /**
+ * Called when a process fails either due to a crash or ANR.
+ *
+ * <p>All registered observers for the packages contained in the process will be notified in
+ * order of priority until an observer signifies that it has taken action and other observers
+ * should not notified.
+ *
+ * <p>This method could be called frequently if there is a severe problem on the device.
+ */
+ public void onPackageFailure(String[] packages) {
+ ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
+ synchronized (mLock) {
+ if (mRegisteredObservers.isEmpty()) {
+ return;
+ }
+
+ for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+ for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+ // Observers interested in receiving packageName failures
+ List<PackageHealthObserver> observersToNotify = new ArrayList<>();
+ PackageHealthObserver activeObserver =
+ mRegisteredObservers.get(mAllObservers.valueAt(oIndex).mName);
+ if (activeObserver != null) {
+ observersToNotify.add(activeObserver);
+ }
+
+ // Save interested observers and notify them outside the lock
+ if (!observersToNotify.isEmpty()) {
+ packagesToReport.put(packages[pIndex], observersToNotify);
+ }
+ }
+ }
+ }
+
+ // Notify observers
+ for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
+ List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
+ for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
+ if (observers.get(oIndex).onHealthCheckFailed(packages[pIndex])) {
+ // Observer has handled, do not notify others
+ break;
+ }
+ }
+ }
+ }
+
+ // TODO(zezeozue): Optimize write? Maybe only write a separate smaller file?
+ // This currently adds about 7ms extra to shutdown thread
+ /** Writes the package information to file during shutdown. */
+ public void writeNow() {
+ if (!mAllObservers.isEmpty()) {
+ mIoHandler.removeCallbacks(this::saveToFile);
+ pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastRescheduleMs);
+ saveToFile();
+ Slog.i(TAG, "Last write to update package durations");
+ }
+ }
+
+ /** Register instances of this interface to receive notifications on package failure. */
+ public interface PackageHealthObserver {
+ /**
+ * Called when health check fails for the {@code packageName}.
+ * @return {@code true} if action was taken and other observers should not be notified of
+ * this failure, {@code false} otherwise.
+ */
+ boolean onHealthCheckFailed(String packageName);
+
+ // TODO(zezeozue): Ensure uniqueness?
+ /**
+ * Identifier for the observer, should not change across device updates otherwise the
+ * watchdog may drop observing packages with the old name.
+ */
+ String getName();
+ }
+
+ /** Reschedules handler to prune expired packages from observers. */
+ private void rescheduleCleanup() {
+ synchronized (mLock) {
+ long nextDurationToScheduleMs = getEarliestPackageExpiryLocked();
+ if (nextDurationToScheduleMs == Long.MAX_VALUE) {
+ Slog.i(TAG, "No monitored packages, ending package cleanup");
+ mDurationAtLastReschedule = 0;
+ mUptimeAtLastRescheduleMs = 0;
+ return;
+ }
+ long uptimeMs = SystemClock.uptimeMillis();
+ // O if mPackageCleanup not running
+ long elapsedDurationMs = mUptimeAtLastRescheduleMs == 0
+ ? 0 : uptimeMs - mUptimeAtLastRescheduleMs;
+ // O if mPackageCleanup not running
+ long remainingDurationMs = mDurationAtLastReschedule - elapsedDurationMs;
+
+ if (mUptimeAtLastRescheduleMs == 0 || nextDurationToScheduleMs < remainingDurationMs) {
+ // First schedule or an earlier reschedule
+ pruneObservers(elapsedDurationMs);
+ mTimerHandler.removeCallbacks(mPackageCleanup);
+ mTimerHandler.postDelayed(mPackageCleanup, nextDurationToScheduleMs);
+ mDurationAtLastReschedule = nextDurationToScheduleMs;
+ mUptimeAtLastRescheduleMs = uptimeMs;
+ }
+ }
+ }
+
+ /**
+ * Returns the earliest time a package should expire.
+ * @returns Long#MAX_VALUE if there are no observed packages.
+ */
+ private long getEarliestPackageExpiryLocked() {
+ long shortestDurationMs = Long.MAX_VALUE;
+ for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+ ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex).mPackages;
+ for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+ long duration = packages.valueAt(pIndex).mDurationMs;
+ if (duration < shortestDurationMs) {
+ shortestDurationMs = duration;
+ }
+ }
+ }
+ Slog.v(TAG, "Earliest package time is " + shortestDurationMs);
+ return shortestDurationMs;
+ }
+
+ /**
+ * Removes {@code elapsedMs} milliseconds from all durations on monitored packages.
+ * Discards expired packages and discards observers without any packages.
+ */
+ private void pruneObservers(long elapsedMs) {
+ if (elapsedMs == 0) {
+ return;
+ }
+ synchronized (mLock) {
+ Slog.d(TAG, "Removing expired packages after " + elapsedMs + "ms");
+ Iterator<ObserverInternal> it = mAllObservers.values().iterator();
+ while (it.hasNext()) {
+ ObserverInternal observer = it.next();
+ if (!observer.updateMonitoringDurations(elapsedMs)) {
+ Slog.i(TAG, "Discarding observer " + observer.mName + ". All packages expired");
+ it.remove();
+ }
+ }
+ }
+ saveToFileAsync();
+ }
+
+ /**
+ * Loads mAllObservers from file.
+ *
+ * <p>Note that this is <b>not</b> thread safe and should only called be called
+ * from the constructor.
+ */
+ private void loadFromFile() {
+ InputStream infile = null;
+ mAllObservers.clear();
+ try {
+ infile = mPolicyFile.openRead();
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(infile, StandardCharsets.UTF_8.name());
+ XmlUtils.beginDocument(parser, TAG_PACKAGE_WATCHDOG);
+ int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ ObserverInternal observer = ObserverInternal.read(parser);
+ if (observer != null) {
+ mAllObservers.put(observer.mName, observer);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // Nothing to monitor
+ } catch (IOException | NumberFormatException | XmlPullParserException e) {
+ Log.wtf(TAG, "Unable to read monitored packages, deleting file", e);
+ mPolicyFile.delete();
+ } finally {
+ IoUtils.closeQuietly(infile);
+ }
+ }
+
+ /**
+ * Persists mAllObservers to file. Threshold information is ignored.
+ */
+ private boolean saveToFile() {
+ synchronized (mLock) {
+ FileOutputStream stream;
+ try {
+ stream = mPolicyFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Cannot update monitored packages", e);
+ return false;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, TAG_PACKAGE_WATCHDOG);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+ mAllObservers.valueAt(oIndex).write(out);
+ }
+ out.endTag(null, TAG_PACKAGE_WATCHDOG);
+ out.endDocument();
+ mPolicyFile.finishWrite(stream);
+ return true;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save monitored packages, restoring backup", e);
+ mPolicyFile.failWrite(stream);
+ return false;
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+ }
+ }
+
+ private void saveToFileAsync() {
+ mIoHandler.removeCallbacks(this::saveToFile);
+ mIoHandler.post(this::saveToFile);
+ }
+
+ /**
+ * Represents an observer monitoring a set of packages along with the failure thresholds for
+ * each package.
+ */
+ static class ObserverInternal {
+ public final String mName;
+ public final ArrayMap<String, MonitoredPackage> mPackages;
+
+ ObserverInternal(String name, List<MonitoredPackage> packages) {
+ mName = name;
+ mPackages = new ArrayMap<>();
+ updatePackages(packages);
+ }
+
+ /**
+ * Writes important details to file. Doesn't persist any package failure thresholds.
+ *
+ * <p>Note that this method is <b>not</b> thread safe. It should only be called from
+ * #saveToFile which runs on a single threaded handler.
+ */
+ public boolean write(XmlSerializer out) {
+ try {
+ out.startTag(null, TAG_OBSERVER);
+ out.attribute(null, ATTR_NAME, mName);
+ for (int i = 0; i < mPackages.size(); i++) {
+ MonitoredPackage p = mPackages.valueAt(i);
+ out.startTag(null, TAG_PACKAGE);
+ out.attribute(null, ATTR_NAME, p.mName);
+ out.attribute(null, ATTR_DURATION, String.valueOf(p.mDurationMs));
+ out.endTag(null, TAG_PACKAGE);
+ }
+ out.endTag(null, TAG_OBSERVER);
+ return true;
+ } catch (IOException e) {
+ Slog.w(TAG, "Cannot save observer", e);
+ return false;
+ }
+ }
+
+ public void updatePackages(List<MonitoredPackage> packages) {
+ synchronized (mName) {
+ for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+ MonitoredPackage p = packages.get(pIndex);
+ mPackages.put(p.mName, p);
+ }
+ }
+ }
+
+ /**
+ * Reduces the monitoring durations of all packages observed by this observer by
+ * {@code elapsedMs}. If any duration is less than 0, the package is removed from
+ * observation.
+ *
+ * @returns {@code true} if there are still packages to be observed, {@code false} otherwise
+ */
+ public boolean updateMonitoringDurations(long elapsedMs) {
+ List<MonitoredPackage> packages = new ArrayList<>();
+ synchronized (mName) {
+ Iterator<MonitoredPackage> it = mPackages.values().iterator();
+ while (it.hasNext()) {
+ MonitoredPackage p = it.next();
+ long newDuration = p.mDurationMs - elapsedMs;
+ if (newDuration > 0) {
+ p.mDurationMs = newDuration;
+ } else {
+ it.remove();
+ }
+ }
+ return !mPackages.isEmpty();
+ }
+ }
+
+ /**
+ * Increments failure counts of {@code packageName}.
+ * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
+ */
+ public boolean onPackageFailure(String packageName) {
+ synchronized (mName) {
+ MonitoredPackage p = mPackages.get(packageName);
+ if (p != null) {
+ return p.onFailure();
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns one ObserverInternal from the {@code parser} and advances its state.
+ *
+ * <p>Note that this method is <b>not</b> thread safe. It should only be called from
+ * #loadFromFile which in turn is only called on construction of the
+ * singleton PackageWatchdog.
+ **/
+ public static ObserverInternal read(XmlPullParser parser) {
+ String observerName = null;
+ if (TAG_OBSERVER.equals(parser.getName())) {
+ observerName = parser.getAttributeValue(null, ATTR_NAME);
+ if (TextUtils.isEmpty(observerName)) {
+ return null;
+ }
+ }
+ List<MonitoredPackage> packages = new ArrayList<>();
+ int innerDepth = parser.getDepth();
+ try {
+ while (XmlUtils.nextElementWithin(parser, innerDepth)) {
+ if (TAG_PACKAGE.equals(parser.getName())) {
+ String packageName = parser.getAttributeValue(null, ATTR_NAME);
+ long duration = Long.parseLong(
+ parser.getAttributeValue(null, ATTR_DURATION));
+ if (!TextUtils.isEmpty(packageName)) {
+ packages.add(new MonitoredPackage(packageName, duration));
+ }
+ }
+ }
+ } catch (IOException e) {
+ return null;
+ } catch (XmlPullParserException e) {
+ return null;
+ }
+ if (packages.isEmpty()) {
+ return null;
+ }
+ return new ObserverInternal(observerName, packages);
+ }
+ }
+
+ /** Represents a package along with the time it should be monitored for. */
+ static class MonitoredPackage {
+ public final String mName;
+ // System uptime duration to monitor package
+ public long mDurationMs;
+ // System uptime of first package failure
+ private long mUptimeStartMs;
+ // Number of failures since mUptimeStartMs
+ private int mFailures;
+
+ MonitoredPackage(String name, long durationMs) {
+ mName = name;
+ mDurationMs = durationMs;
+ }
+
+ /**
+ * Increment package failures or resets failure count depending on the last package failure.
+ *
+ * @return {@code true} if failure count exceeds a threshold, {@code false} otherwise
+ */
+ public synchronized boolean onFailure() {
+ final long now = SystemClock.uptimeMillis();
+ final long duration = now - mUptimeStartMs;
+ if (duration > TRIGGER_DURATION_MS) {
+ // TODO(zezeozue): Reseting to 1 is not correct
+ // because there may be more than 1 failure in the last trigger window from now
+ // This is the RescueParty impl, will leave for now
+ mFailures = 1;
+ mUptimeStartMs = now;
+ } else {
+ mFailures++;
+ }
+ return mFailures >= TRIGGER_FAILURE_COUNT;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d07cf78e47ed..e10e0d6ef1ce 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1313,16 +1313,17 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyDataConnection(int state, boolean isDataAllowed,
- String reason, String apn, String apnType, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+ public void notifyDataConnection(int state, boolean isDataAllowed, String apn, String apnType,
+ LinkProperties linkProperties,
+ NetworkCapabilities networkCapabilities, int networkType,
+ boolean roaming) {
notifyDataConnectionForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state,
- isDataAllowed,reason, apn, apnType, linkProperties,
- networkCapabilities, networkType, roaming);
+ isDataAllowed, apn, apnType, linkProperties,
+ networkCapabilities, networkType, roaming);
}
- public void notifyDataConnectionForSubscriber(int subId, int state,
- boolean isDataAllowed, String reason, String apn, String apnType,
+ public void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataAllowed,
+ String apn, String apnType,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int networkType, boolean roaming) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
@@ -1331,7 +1332,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (VDBG) {
log("notifyDataConnectionForSubscriber: subId=" + subId
+ " state=" + state + " isDataAllowed=" + isDataAllowed
- + " reason='" + reason
+ "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
+ " mRecords.size()=" + mRecords.size());
}
@@ -1366,7 +1366,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mDataConnectionNetworkType[phoneId] = networkType;
}
mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
- apnType, apn, reason, linkProperties, "");
+ apnType, apn, linkProperties, "");
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1381,30 +1381,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
handleRemoveListLocked();
}
- broadcastDataConnectionStateChanged(state, isDataAllowed, reason, apn,
- apnType, linkProperties, networkCapabilities, roaming, subId);
- broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
+ broadcastDataConnectionStateChanged(state, isDataAllowed, apn, apnType, linkProperties,
+ networkCapabilities, roaming, subId);
+ broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn,
linkProperties, "");
}
- public void notifyDataConnectionFailed(String reason, String apnType) {
+ public void notifyDataConnectionFailed(String apnType) {
notifyDataConnectionFailedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
- reason, apnType);
+ apnType);
}
- public void notifyDataConnectionFailedForSubscriber(int subId,
- String reason, String apnType) {
+ public void notifyDataConnectionFailedForSubscriber(int subId, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
}
if (VDBG) {
log("notifyDataConnectionFailedForSubscriber: subId=" + subId
- + " reason=" + reason + " apnType=" + apnType);
+ + " apnType=" + apnType);
}
synchronized (mRecords) {
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
- apnType, "", reason, null, "");
+ apnType, "", null, "");
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1417,9 +1416,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
handleRemoveListLocked();
}
- broadcastDataConnectionFailed(reason, apnType, subId);
+ broadcastDataConnectionFailed(apnType, subId);
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", null, "");
}
public void notifyCellLocation(Bundle cellLocation) {
@@ -1529,15 +1528,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyPreciseDataConnectionFailed(String reason, String apnType,
- String apn, String failCause) {
+ public void notifyPreciseDataConnectionFailed(String apnType, String apn, String failCause) {
if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
return;
}
synchronized (mRecords) {
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- apnType, apn, reason, null, failCause);
+ apnType, apn, null, failCause);
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1551,7 +1549,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
handleRemoveListLocked();
}
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, null, failCause);
}
@Override
@@ -1881,10 +1879,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_CALL_LOG});
}
- private void broadcastDataConnectionStateChanged(int state,
- boolean isDataAllowed,
- String reason, String apn, String apnType, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, boolean roaming, int subId) {
+ private void broadcastDataConnectionStateChanged(int state, boolean isDataAllowed, String apn,
+ String apnType, LinkProperties linkProperties,
+ NetworkCapabilities networkCapabilities,
+ boolean roaming, int subId) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -1894,9 +1892,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (!isDataAllowed) {
intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
}
- if (reason != null) {
- intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
- }
if (linkProperties != null) {
intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
String iface = linkProperties.getInterfaceName();
@@ -1915,17 +1910,15 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastDataConnectionFailed(String reason, String apnType,
- int subId) {
+ private void broadcastDataConnectionFailed(String apnType, int subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
- intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
- int backgroundCallState) {
+ int backgroundCallState) {
Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
@@ -1935,16 +1928,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
- String apnType, String apn, String reason, LinkProperties linkProperties,
- String failCause) {
+ String apnType, String apn,
+ LinkProperties linkProperties,
+ String failCause) {
Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
intent.putExtra(PhoneConstants.STATE_KEY, state);
intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
- if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
if (linkProperties != null) {
- intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY,linkProperties);
+ intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
}
if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index e80e9e1b594e..1aeb6898fa13 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -91,6 +91,7 @@ public class Watchdog extends Thread {
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
+ "/system/bin/vold",
"media.extractor", // system/bin/mediaextractor
"media.metrics", // system/bin/mediametrics
"media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a94fa12e4f35..ed39d8302bf7 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2503,6 +2503,9 @@ public final class ActiveServices {
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
+ if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
+ hostingType = "app_zygote";
+ }
}
// Not running -- get it started, and enqueue this service record
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1a5dd90b918a..bc21610dd602 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -235,6 +235,7 @@ import android.media.audiofx.AudioEffect;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
+import android.os.AppZygote;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.BinderProxy;
@@ -336,6 +337,7 @@ import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.NetworkManagementInternal;
+import com.android.server.PackageWatchdog;
import com.android.server.RescueParty;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
@@ -451,6 +453,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
+ // How long we wait to kill an application zygote, after the last process using
+ // it has gone away.
+ static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
/**
* How long we wait for an provider to be published. Should be longer than
* {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
@@ -587,6 +592,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public final PendingIntentController mPendingIntentController;
final AppErrors mAppErrors;
+ final PackageWatchdog mPackageWatchdog;
/**
* Indicates the maximum time spent waiting for the network rules to get updated.
@@ -1439,6 +1445,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
+ static final int KILL_APP_ZYGOTE_MSG = 71;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1642,6 +1649,12 @@ public class ActivityManagerService extends IActivityManager.Stub
false, userId, reason);
}
} break;
+ case KILL_APP_ZYGOTE_MSG: {
+ synchronized (ActivityManagerService.this) {
+ final AppZygote appZygote = (AppZygote) msg.obj;
+ mProcessList.killAppZygoteIfNeededLocked(appZygote);
+ }
+ } break;
case CHECK_EXCESSIVE_POWER_USE_MSG: {
synchronized (ActivityManagerService.this) {
checkExcessivePowerUsageLocked();
@@ -1930,7 +1943,8 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
false,
- 0);
+ 0,
+ false);
app.setPersistent(true);
app.pid = MY_PID;
app.getWindowProcessController().setPid(MY_PID);
@@ -2209,6 +2223,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mContext = mInjector.getContext();
mUiContext = null;
mAppErrors = null;
+ mPackageWatchdog = null;
mActiveUids = new ActiveUids(this, false /* postChangesToAtm */);
mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
mBatteryStatsService = null;
@@ -2275,7 +2290,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mServices = new ActiveServices(this);
mProviderMap = new ProviderMap(this);
- mAppErrors = new AppErrors(mUiContext, this);
+ mPackageWatchdog = PackageWatchdog.getInstance(mUiContext);
+ mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog);
mActiveUids = new ActiveUids(this, true /* postChangesToAtm */);
final File systemDir = SystemServiceManager.ensureSystemDir();
@@ -3740,10 +3756,10 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
- resolvedUserId);
+ resolvedUserId, false);
} else {
broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
- null, null, null, null, false, false, resolvedUserId);
+ null, null, null, null, false, false, resolvedUserId, false);
}
if (observer != null) {
@@ -7392,7 +7408,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app == null) {
- app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0);
+ app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false);
mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
@@ -13992,7 +14008,7 @@ public class ActivityManagerService extends IActivityManager.Stub
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1);
+ null, 0, null, null, false, true, true, -1, false);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
@@ -14231,6 +14247,18 @@ public class ActivityManagerService extends IActivityManager.Stub
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+ return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
+ resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
+ sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
+ }
+
+ @GuardedBy("this")
+ final int broadcastIntentLocked(ProcessRecord callerApp,
+ String callerPackage, Intent intent, String resolvedType,
+ IIntentReceiver resultTo, int resultCode, String resultData,
+ Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
+ boolean allowBackgroundActivityStarts) {
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14731,7 +14759,8 @@ public class ActivityManagerService extends IActivityManager.Stub
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
- resultCode, resultData, resultExtras, ordered, sticky, false, userId);
+ resultCode, resultData, resultExtras, ordered, sticky, false, userId,
+ allowBackgroundActivityStarts);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14827,7 +14856,8 @@ public class ActivityManagerService extends IActivityManager.Stub
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
- resultData, resultExtras, ordered, sticky, false, userId);
+ resultData, resultExtras, ordered, sticky, false, userId,
+ allowBackgroundActivityStarts);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
@@ -14974,7 +15004,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- int userId) {
+ int userId, boolean allowBackgroundActivityStarts) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -14984,7 +15014,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
resultTo, resultCode, resultData, resultExtras,
requiredPermissions, OP_NONE, bOptions, serialized,
- sticky, -1, uid, userId);
+ sticky, -1, uid, userId, allowBackgroundActivityStarts);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -19040,6 +19070,19 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
+ IBinder whitelistToken, int flags) {
+ if (!(target instanceof PendingIntentRecord)) {
+ Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():"
+ + " not a PendingIntentRecord: " + target);
+ return;
+ }
+ synchronized (ActivityManagerService.this) {
+ ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags);
+ }
+ }
+
+ @Override
public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
synchronized (ActivityManagerService.this) {
mDeviceIdleWhitelist = allAppids;
@@ -19426,11 +19469,12 @@ public class ActivityManagerService extends IActivityManager.Stub
public int broadcastIntentInPackage(String packageName, int uid, Intent intent,
String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized,
- boolean sticky, int userId) {
+ boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
synchronized (ActivityManagerService.this) {
return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
- requiredPermission, bOptions, serialized, sticky, userId);
+ requiredPermission, bOptions, serialized, sticky, userId,
+ allowBackgroundActivityStarts);
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 1c1daffceafe..a634b577f506 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -53,6 +53,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.server.PackageWatchdog;
import com.android.server.RescueParty;
import com.android.server.wm.WindowProcessController;
@@ -69,6 +70,7 @@ class AppErrors {
private final ActivityManagerService mService;
private final Context mContext;
+ private final PackageWatchdog mPackageWatchdog;
private ArraySet<String> mAppsNotReportingCrashes;
@@ -93,10 +95,11 @@ class AppErrors {
private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
- AppErrors(Context context, ActivityManagerService service) {
+ AppErrors(Context context, ActivityManagerService service, PackageWatchdog watchdog) {
context.assertRuntimeOverlayThemable();
mService = service;
mContext = context;
+ mPackageWatchdog = watchdog;
}
void writeToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
@@ -400,10 +403,16 @@ class AppErrors {
longMsg = shortMsg;
}
- // If a persistent app is stuck in a crash loop, the device isn't very
- // usable, so we want to consider sending out a rescue party.
- if (r != null && r.isPersistent()) {
- RescueParty.notePersistentAppCrash(mContext, r.uid);
+ if (r != null) {
+ if (r.isPersistent()) {
+ // If a persistent app is stuck in a crash loop, the device isn't very
+ // usable, so we want to consider sending out a rescue party.
+ RescueParty.notePersistentAppCrash(mContext, r.uid);
+ } else {
+ // If a non-persistent app is stuck in crash loop, we want to inform
+ // the package watchdog, maybe an update or experiment can be rolled back.
+ mPackageWatchdog.onPackageFailure(r.getPackageList());
+ }
}
final int relaunchReason = r != null
@@ -821,6 +830,7 @@ class AppErrors {
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
+ String[] packageList = null;
synchronized (mService) {
AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
final ProcessRecord proc = data.proc;
@@ -828,6 +838,9 @@ class AppErrors {
Slog.e(TAG, "handleShowAnrUi: proc is null");
return;
}
+ if (!proc.isPersistent()) {
+ packageList = proc.getPackageList();
+ }
if (proc.anrDialog != null) {
Slog.e(TAG, "App already has anr dialog: " + proc);
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
@@ -851,6 +864,10 @@ class AppErrors {
if (dialogToShow != null) {
dialogToShow.show();
}
+ // Notify PackageWatchdog without the lock held
+ if (packageList != null) {
+ mPackageWatchdog.onPackageFailure(packageList);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index c290fbe09864..65aacdcb73e0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -287,6 +287,9 @@ 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();
@@ -415,6 +418,9 @@ public final class BroadcastQueue {
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
+ if (r.allowBackgroundActivityStarts) {
+ r.curApp.removeAllowBackgroundActivityStartsToken(r);
+ }
// 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) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9b7dc44e5a73..9e799f6f14f3 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -81,6 +81,10 @@ final class BroadcastRecord extends Binder {
int manifestSkipCount; // number of manifest receivers skipped.
BroadcastQueue queue; // the outbound queue handling this broadcast
+ // if set to true, app's process will be temporarily whitelisted to start activities
+ // from background for the duration of the broadcast dispatch
+ final boolean allowBackgroundActivityStarts;
+
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
static final int CALL_IN_RECEIVE = 2;
@@ -223,7 +227,8 @@ final class BroadcastRecord extends Binder {
int _callingPid, int _callingUid, boolean _callerInstantApp, String _resolvedType,
String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
- boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId) {
+ boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
+ boolean _allowBackgroundActivityStarts) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -252,6 +257,7 @@ final class BroadcastRecord extends Binder {
userId = _userId;
nextReceiver = 0;
state = IDLE;
+ allowBackgroundActivityStarts = _allowBackgroundActivityStarts;
}
/**
@@ -295,6 +301,7 @@ final class BroadcastRecord extends Binder {
manifestCount = from.manifestCount;
manifestSkipCount = from.manifestSkipCount;
queue = from.queue;
+ allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
}
public BroadcastRecord maybeStripForHistory() {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 65cd329b5de8..f9a77af631af 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -67,8 +67,8 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
- String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACK_LIST, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 447243b542ea..b675d9d4f9cf 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -34,6 +34,7 @@ import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -48,6 +49,9 @@ import java.util.Objects;
public final class PendingIntentRecord extends IIntentSender.Stub {
private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
+ public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
+ public static final int FLAG_BROADCAST_SENDER = 1 << 1;
+
final PendingIntentController controller;
final Key key;
final int uid;
@@ -56,6 +60,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
boolean canceled = false;
private ArrayMap<IBinder, Long> whitelistDuration;
private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
+ private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
+ private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
String stringName;
String lastTagPrefix;
@@ -214,6 +220,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
this.stringName = null;
}
+ void setAllowBgActivityStarts(IBinder token, int flags) {
+ if (token == null) return;
+ if ((flags & FLAG_ACTIVITY_SENDER) != 0) {
+ mAllowBgActivityStartsForActivitySender.add(token);
+ }
+ if ((flags & FLAG_BROADCAST_SENDER) != 0) {
+ mAllowBgActivityStartsForBroadcastSender.add(token);
+ }
+ }
+
public void registerCancelListenerLocked(IResultReceiver receiver) {
if (mCancelCallbacks == null) {
mCancelCallbacks = new RemoteCallbackList<>();
@@ -370,14 +386,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
res = controller.mAtmInternal.startActivitiesInPackage(
uid, key.packageName, allIntents, allResolvedTypes, resultTo,
mergedOptions, userId, false /* validateIncomingUser */,
- this /* originatingPendingIntent */);
+ this /* originatingPendingIntent */,
+ mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
} else {
res = controller.mAtmInternal.startActivityInPackage(
uid, callingPid, callingUid, key.packageName, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
mergedOptions, userId, null, "PendingIntentRecord",
false /* validateIncomingUser */,
- this /* originatingPendingIntent */);
+ this /* originatingPendingIntent */,
+ mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -394,7 +412,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
requiredPermission, options, (finishedReceiver != null),
- false, userId);
+ false, userId,
+ mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 117984e10cf5..9898d06837be 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -19,8 +19,6 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
-import static android.os.Process.FIRST_ISOLATED_UID;
-import static android.os.Process.LAST_ISOLATED_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.getFreeMemory;
@@ -34,6 +32,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS;
+import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG;
import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT;
import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT_MSG;
@@ -58,6 +58,7 @@ import android.graphics.Point;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.Uri;
+import android.os.AppZygote;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -75,10 +76,12 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.EventLog;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.StatsLog;
import android.view.Display;
@@ -108,6 +111,7 @@ import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.List;
/**
@@ -354,10 +358,136 @@ public final class ProcessList {
final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
/**
- * Counter for assigning isolated process uids, to avoid frequently reusing the
- * same ones.
+ * The currently running application zygotes.
*/
- int mNextIsolatedProcessUid = 0;
+ final ProcessMap<AppZygote> mAppZygotes = new ProcessMap<AppZygote>();
+
+ /**
+ * The processes that are forked off an application zygote.
+ */
+ final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
+ new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+
+ final class IsolatedUidRange {
+ @VisibleForTesting
+ public final int mFirstUid;
+ @VisibleForTesting
+ public final int mLastUid;
+
+ @GuardedBy("ProcessList.this.mService")
+ private final SparseBooleanArray mUidUsed = new SparseBooleanArray();
+
+ @GuardedBy("ProcessList.this.mService")
+ private int mNextUid;
+
+ IsolatedUidRange(int firstUid, int lastUid) {
+ mFirstUid = firstUid;
+ mLastUid = lastUid;
+ mNextUid = firstUid;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ int allocateIsolatedUidLocked(int userId) {
+ int uid;
+ int stepsLeft = (mLastUid - mFirstUid + 1);
+ for (int i = 0; i < stepsLeft; ++i) {
+ if (mNextUid < mFirstUid || mNextUid > mLastUid) {
+ mNextUid = mFirstUid;
+ }
+ uid = UserHandle.getUid(userId, mNextUid);
+ mNextUid++;
+ if (!mUidUsed.get(uid, false)) {
+ mUidUsed.put(uid, true);
+ return uid;
+ }
+ }
+ return -1;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ void freeIsolatedUidLocked(int uid) {
+ // Strip out userId
+ final int appId = UserHandle.getAppId(uid);
+ mUidUsed.delete(appId);
+ }
+ };
+
+ /**
+ * A class that allocates ranges of isolated UIDs per application, and keeps track of them.
+ */
+ final class IsolatedUidRangeAllocator {
+ private final int mFirstUid;
+ private final int mNumUidRanges;
+ private final int mNumUidsPerRange;
+ /**
+ * We map the uid range [mFirstUid, mFirstUid + mNumUidRanges * mNumUidsPerRange)
+ * back to an underlying bitset of [0, mNumUidRanges) and allocate out of that.
+ */
+ @GuardedBy("ProcessList.this.mService")
+ private final BitSet mAvailableUidRanges;
+ @GuardedBy("ProcessList.this.mService")
+ private final ProcessMap<IsolatedUidRange> mAppRanges = new ProcessMap<IsolatedUidRange>();
+
+ IsolatedUidRangeAllocator(int firstUid, int lastUid, int numUidsPerRange) {
+ mFirstUid = firstUid;
+ mNumUidsPerRange = numUidsPerRange;
+ mNumUidRanges = (lastUid - firstUid + 1) / numUidsPerRange;
+ mAvailableUidRanges = new BitSet(mNumUidRanges);
+ // Mark all as available
+ mAvailableUidRanges.set(0, mNumUidRanges);
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) {
+ return mAppRanges.get(info.processName, info.uid);
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) {
+ IsolatedUidRange range = getIsolatedUidRangeLocked(info);
+ if (range == null) {
+ int uidRangeIndex = mAvailableUidRanges.nextSetBit(0);
+ if (uidRangeIndex < 0) {
+ // No free range
+ return null;
+ }
+ mAvailableUidRanges.clear(uidRangeIndex);
+ int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange;
+ range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1);
+ mAppRanges.put(info.processName, info.uid, range);
+ }
+ return range;
+ }
+
+ @GuardedBy("ProcessList.this.mService")
+ void freeUidRangeLocked(ApplicationInfo info) {
+ // Find the UID range
+ IsolatedUidRange range = mAppRanges.get(info.processName, info.uid);
+ if (range != null) {
+ // Map back to starting uid
+ final int uidRangeIndex = (range.mFirstUid - mFirstUid) / mNumUidsPerRange;
+ // Mark it as available in the underlying bitset
+ mAvailableUidRanges.set(uidRangeIndex);
+ // And the map
+ mAppRanges.remove(info.processName, info.uid);
+ }
+ }
+ }
+
+ /**
+ * The available isolated UIDs for processes that are not spawned from an application zygote.
+ */
+ @VisibleForTesting
+ IsolatedUidRange mGlobalIsolatedUids = new IsolatedUidRange(Process.FIRST_ISOLATED_UID,
+ Process.LAST_ISOLATED_UID);
+
+ /**
+ * An allocator for isolated UID ranges for apps that use an application zygote.
+ */
+ @VisibleForTesting
+ IsolatedUidRangeAllocator mAppIsolatedUidRangeAllocator =
+ new IsolatedUidRangeAllocator(Process.FIRST_APP_ZYGOTE_ISOLATED_UID,
+ Process.LAST_APP_ZYGOTE_ISOLATED_UID, Process.NUM_UIDS_PER_APP_ZYGOTE);
/**
* Processes that are being forcibly torn down.
@@ -1362,8 +1492,9 @@ public final class ProcessList {
mService.mNativeDebuggingApp = null;
}
- if (app.info.isPrivilegedApp() &&
- DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
+ if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0
+ || (app.info.isPrivilegedApp()
+ && DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet()))) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
@@ -1504,6 +1635,67 @@ public final class ProcessList {
}
}
+ @GuardedBy("mService")
+ public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
+ final ApplicationInfo appInfo = appZygote.getAppInfo();
+ ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
+ if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now
+ mAppZygotes.remove(appInfo.processName, appInfo.uid);
+ mAppZygoteProcesses.remove(appZygote);
+ mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
+ appZygote.stopZygote();
+ }
+ }
+
+ @GuardedBy("mService")
+ private void removeProcessFromAppZygoteLocked(final ProcessRecord app) {
+ // Free the isolated uid for this process
+ final IsolatedUidRange appUidRange =
+ mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+ if (appUidRange != null) {
+ appUidRange.freeIsolatedUidLocked(app.uid);
+ }
+
+ final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
+ if (appZygote != null) {
+ ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
+ zygoteProcesses.remove(app);
+ if (zygoteProcesses.size() == 0) {
+ Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
+ msg.obj = appZygote;
+ mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
+ }
+ }
+ }
+
+ private AppZygote createAppZygoteForProcessIfNeeded(final ProcessRecord app) {
+ synchronized (mService) {
+ AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
+ final ArrayList<ProcessRecord> zygoteProcessList;
+ if (appZygote == null) {
+ final int userId = UserHandle.getUserId(app.info.uid);
+ final IsolatedUidRange uidRange =
+ mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+ // Allocate an isolated UID out of this range for the Zygote itself
+ final int zygoteIsolatedUid = uidRange.allocateIsolatedUidLocked(userId);
+ appZygote = new AppZygote(app.info, zygoteIsolatedUid);
+ mAppZygotes.put(app.info.processName, app.info.uid, appZygote);
+ zygoteProcessList = new ArrayList<ProcessRecord>();
+ mAppZygoteProcesses.put(appZygote, zygoteProcessList);
+ } else {
+ mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG, appZygote);
+ zygoteProcessList = mAppZygoteProcesses.get(appZygote);
+ }
+ // Note that we already add the app to mAppZygoteProcesses here;
+ // this is so that another thread can't come in and kill the zygote
+ // before we've even tried to start the process. If the process launch
+ // goes wrong, we'll clean this up in removeProcessNameLocked()
+ zygoteProcessList.add(app);
+
+ return appZygote;
+ }
+ }
+
private Process.ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
@@ -1524,6 +1716,15 @@ public final class ProcessList {
app.info.dataDir, null, app.info.packageName,
packageNames, visibleVolIds,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ } else if (hostingType.equals("app_zygote")) {
+ final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
+
+ startResult = appZygote.getProcess().start(entryPoint,
+ app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+ app.info.dataDir, null, app.info.packageName,
+ packageNames, visibleVolIds,
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq});
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
@@ -1628,8 +1829,9 @@ public final class ProcessList {
? hostingName.flattenToShortString() : null;
if (app == null) {
+ final boolean fromAppZygote = "app_zygote".equals(hostingType);
checkSlow(startTime, "startProcess: creating new process record");
- app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
+ app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote);
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
@@ -2002,29 +2204,31 @@ public final class ProcessList {
}
@GuardedBy("mService")
+ private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info,
+ boolean fromAppZygote) {
+ if (!fromAppZygote) {
+ // Allocate an isolated UID from the global range
+ return mGlobalIsolatedUids;
+ } else {
+ return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info);
+ }
+ }
+
+ @GuardedBy("mService")
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated, int isolatedUid) {
+ boolean isolated, int isolatedUid, boolean fromAppZygote) {
String proc = customProcess != null ? customProcess : info.processName;
final int userId = UserHandle.getUserId(info.uid);
int uid = info.uid;
if (isolated) {
if (isolatedUid == 0) {
- int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
- while (true) {
- if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
- }
- uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
- mNextIsolatedProcessUid++;
- if (mIsolatedProcesses.indexOfKey(uid) < 0) {
- // No process for this uid, use it.
- break;
- }
- stepsLeft--;
- if (stepsLeft <= 0) {
- return null;
- }
+ IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote);
+ if (uidRange == null) {
+ return null;
+ }
+ uid = uidRange.allocateIsolatedUidLocked(userId);
+ if (uid == -1) {
+ return null;
}
} else {
// Special case for startIsolatedProcess (internal only), where
@@ -2092,6 +2296,13 @@ public final class ProcessList {
old.uidRecord = null;
}
mIsolatedProcesses.remove(uid);
+ mGlobalIsolatedUids.freeIsolatedUidLocked(uid);
+ // Remove the (expected) ProcessRecord from the app zygote
+ final ProcessRecord record = expecting != null ? expecting : old;
+ if (record != null && record.appZygote) {
+ removeProcessFromAppZygoteLocked(record);
+ }
+
return old;
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c15b7c7d82c2..0d0824a74cdd 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -76,6 +76,7 @@ final class ProcessRecord implements WindowProcessListener {
private final ActivityManagerService mService; // where we came from
final ApplicationInfo info; // all about the first app in the process
final boolean isolated; // true if this is a special isolated process
+ final boolean appZygote; // true if this is forked from the app zygote
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
@@ -249,6 +250,9 @@ final class ProcessRecord implements WindowProcessListener {
final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
// All ContentProviderRecord process is using
final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();
+ // A set of tokens that currently contribute to this process being temporarily whitelisted
+ // to start activities even if it's not in the foreground
+ final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
String isolatedEntryPoint; // Class to run on start if this is a special isolated process.
String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -556,6 +560,8 @@ final class ProcessRecord implements WindowProcessListener {
mService = _service;
info = _info;
isolated = _info.uid != _uid;
+ appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
uid = _uid;
userId = UserHandle.getUserId(_uid);
processName = _processName;
@@ -1135,6 +1141,17 @@ final class ProcessRecord implements WindowProcessListener {
return mUsingWrapper;
}
+ void addAllowBackgroundActivityStartsToken(Binder entity) {
+ mAllowBackgroundActivityStartsTokens.add(entity);
+ mWindowProcessController.setAllowBackgroundActivityStarts(true);
+ }
+
+ void removeAllowBackgroundActivityStartsToken(Binder entity) {
+ mAllowBackgroundActivityStartsTokens.remove(entity);
+ mWindowProcessController.setAllowBackgroundActivityStarts(
+ !mAllowBackgroundActivityStartsTokens.isEmpty());
+ }
+
void setActiveInstrumentation(ActiveInstrumentation instr) {
mInstr = instr;
mWindowProcessController.setInstrumenting(instr != null);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6cde4adb9f11..d704a3ea8eb1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7822,6 +7822,36 @@ public class AudioService extends IAudioService.Stub
return AudioManager.SUCCESS;
}
+ /** see AudioPolicy.setUidDeviceAffinity() */
+ public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
+ @NonNull int[] deviceTypes,
+ @NonNull String[] deviceAddresses) {
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
+ if (app == null) {
+ return AudioManager.ERROR;
+ }
+ if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
+ return AudioManager.ERROR;
+ }
+ }
+ return AudioManager.SUCCESS;
+ }
+
+ /** see AudioPolicy.removeUidDeviceAffinity() */
+ public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
+ synchronized (mAudioPolicies) {
+ final AudioPolicyProxy app =
+ checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
+ if (app == null) {
+ return AudioManager.ERROR;
+ }
+
+ }
+ return AudioManager.SUCCESS;
+ }
+
public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
+ " policy " + pcb.asBinder());
@@ -7994,6 +8024,15 @@ public class AudioService extends IAudioService.Stub
//======================
// Audio policy proxy
//======================
+ private static final class AudioDeviceArray {
+ final @NonNull int[] mDeviceTypes;
+ final @NonNull String[] mDeviceAddresses;
+ AudioDeviceArray(@NonNull int[] types, @NonNull String[] addresses) {
+ mDeviceTypes = types;
+ mDeviceAddresses = addresses;
+ }
+ }
+
/**
* This internal class inherits from AudioPolicyConfig, each instance contains all the
* mixes of an AudioPolicy and their configurations.
@@ -8003,6 +8042,8 @@ public class AudioService extends IAudioService.Stub
final IAudioPolicyCallback mPolicyCallback;
final boolean mHasFocusListener;
final boolean mIsVolumeController;
+ final HashMap<Integer, AudioDeviceArray> mUidDeviceAffinities =
+ new HashMap<Integer, AudioDeviceArray>();
/**
* Audio focus ducking behavior for an audio policy.
* This variable reflects the value that was successfully set in
@@ -8075,6 +8116,26 @@ public class AudioService extends IAudioService.Stub
return false;
}
+ // Verify all the devices in the array are served by mixes defined in this policy
+ boolean hasMixRoutedToDevices(@NonNull int[] deviceTypes,
+ @NonNull String[] deviceAddresses) {
+ for (int i = 0; i < deviceTypes.length; i++) {
+ boolean hasDevice = false;
+ for (AudioMix mix : mMixes) {
+ // this will check both that the mix has ROUTE_FLAG_RENDER and the device
+ // is reached by this mix
+ if (mix.isRoutedToDevice(deviceTypes[i], deviceAddresses[i])) {
+ hasDevice = true;
+ break;
+ }
+ }
+ if (!hasDevice) {
+ return false;
+ }
+ }
+ return true;
+ }
+
void addMixes(@NonNull ArrayList<AudioMix> mixes) {
// TODO optimize to not have to unregister the mixes already in place
synchronized (mMixes) {
@@ -8098,6 +8159,29 @@ public class AudioService extends IAudioService.Stub
AudioSystem.registerPolicyMixes(mMixes, true);
Binder.restoreCallingIdentity(identity);
}
+
+ void setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+ final Integer Uid = new Integer(uid);
+ if (mUidDeviceAffinities.remove(Uid) != null) {
+ final long identity = Binder.clearCallingIdentity();
+ AudioSystem.removeUidDeviceAffinities(uid);
+ Binder.restoreCallingIdentity(identity);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ final int res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
+ Binder.restoreCallingIdentity(identity);
+ if (res == AudioSystem.SUCCESS) {
+ mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
+ }
+ }
+
+ void removeUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+ if (mUidDeviceAffinities.remove(new Integer(uid)) != null) {
+ final long identity = Binder.clearCallingIdentity();
+ AudioSystem.removeUidDeviceAffinities(uid);
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
};
//======================
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a381477b01cb..36ca4dcbea33 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -373,6 +373,13 @@ public class BiometricService extends SystemService {
public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
throws RemoteException {
try {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+ return;
+ }
+
if (!requireConfirmation) {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
KeyStore.getInstance().addAuthToken(token);
@@ -398,6 +405,13 @@ public class BiometricService extends SystemService {
public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
throws RemoteException {
try {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+ return;
+ }
+
mStatusBarService.onBiometricHelp(getContext().getResources().getString(
com.android.internal.R.string.biometric_not_recognized));
if (requireConfirmation) {
@@ -486,6 +500,13 @@ public class BiometricService extends SystemService {
@Override
public void onAcquired(int acquiredInfo, String message) throws RemoteException {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAcquired(): Auth session is null");
+ return;
+ }
+
if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
try {
mStatusBarService.onBiometricHelp(message);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 52ecccaa7367..78b3c15500ea 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -17,13 +17,6 @@
package com.android.server.display;
import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
-import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
-import android.app.TaskStackListener;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManagerInternal;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -34,8 +27,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.util.EventLog;
@@ -43,15 +34,14 @@ import android.util.MathUtils;
import android.util.Slog;
import android.util.TimeUtils;
-import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
-import com.android.server.LocalServices;
import java.io.PrintWriter;
class AutomaticBrightnessController {
private static final String TAG = "AutomaticBrightnessController";
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
// If true, enables the use of the screen auto-brightness adjustment setting.
@@ -76,8 +66,6 @@ class AutomaticBrightnessController {
private static final int MSG_UPDATE_AMBIENT_LUX = 1;
private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
- private static final int MSG_UPDATE_FOREGROUND_APP = 4;
- private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
// Length of the ambient light horizon used to calculate the long term estimate of ambient
// light.
@@ -138,8 +126,6 @@ class AutomaticBrightnessController {
private final HysteresisLevels mAmbientBrightnessThresholds;
private final HysteresisLevels mScreenBrightnessThresholds;
- private boolean mLoggingEnabled;
-
// Amount of time to delay auto-brightness after screen on while waiting for
// the light sensor to warm-up in milliseconds.
// May be 0 if no warm-up is required.
@@ -206,19 +192,6 @@ class AutomaticBrightnessController {
private float mShortTermModelAnchor;
private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
- // Context-sensitive brightness configurations require keeping track of the foreground app's
- // package name and category, which is done by registering a TaskStackListener to call back to
- // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
- // package namd and PackageManager to get its category (so might as well cache them).
- private int mUserId;
- private String mForegroundAppPackageName;
- private String mPendingForegroundAppPackageName;
- private @ApplicationInfo.Category int mForegroundAppCategory;
- private @ApplicationInfo.Category int mPendingForegroundAppCategory;
- private TaskStackListenerImpl mTaskStackListener;
- private IActivityTaskManager mActivityTaskManager;
- private PackageManagerInternal mPackageManagerInternal;
-
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, BrightnessMappingStrategy mapper,
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -253,42 +226,6 @@ class AutomaticBrightnessController {
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
-
- mUserId = ActivityManager.getCurrentUser();
- mActivityTaskManager = ActivityTaskManager.getService();
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mTaskStackListener = new TaskStackListenerImpl();
- mForegroundAppPackageName = null;
- mPendingForegroundAppPackageName = null;
- mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
- mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
- }
-
- /**
- * Enable/disable logging.
- *
- * @param loggingEnabled
- * Whether logging should be on/off.
- *
- * @return Whether the method succeeded or not.
- */
- public boolean setLoggingEnabled(boolean loggingEnabled) {
- if (mLoggingEnabled == loggingEnabled) {
- return false;
- }
- mBrightnessMapper.setLoggingEnabled(loggingEnabled);
- mLoggingEnabled = loggingEnabled;
- return true;
- }
-
- /**
- * Update the current user's ID.
- *
- * @param userId
- * The current user's ID.
- */
- public void onSwitchUser(int userId) {
- mUserId = userId;
}
public int getAutomaticScreenBrightness() {
@@ -353,7 +290,7 @@ class AutomaticBrightnessController {
}
final int oldPolicy = mDisplayPolicy;
mDisplayPolicy = policy;
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
}
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
@@ -380,7 +317,7 @@ class AutomaticBrightnessController {
mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
mShortTermModelValid = true;
mShortTermModelAnchor = mAmbientLux;
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
}
return true;
@@ -393,7 +330,7 @@ class AutomaticBrightnessController {
}
private void invalidateShortTermModel() {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "ShortTermModel: invalidate user data");
}
mShortTermModelValid = false;
@@ -446,11 +383,7 @@ class AutomaticBrightnessController {
pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
pw.println(" mBrightnessAdjustmentSampleOldBrightness="
+ mBrightnessAdjustmentSampleOldBrightness);
- pw.println(" mUserId=" + mUserId);
- pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName);
- pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
- pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
- pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
+ pw.println(" mShortTermModelValid=" + mShortTermModelValid);
pw.println();
mBrightnessMapper.dump(pw);
@@ -466,7 +399,6 @@ class AutomaticBrightnessController {
mLightSensorEnabled = true;
mLightSensorEnableTime = SystemClock.uptimeMillis();
mCurrentLightSensorRate = mInitialLightSensorRate;
- registerForegroundAppUpdater();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
mCurrentLightSensorRate * 1000, mHandler);
return true;
@@ -479,7 +411,6 @@ class AutomaticBrightnessController {
mAmbientLightRingBuffer.clear();
mCurrentLightSensorRate = -1;
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
- unregisterForegroundAppUpdater();
mSensorManager.unregisterListener(mLightSensorListener);
}
return false;
@@ -510,7 +441,7 @@ class AutomaticBrightnessController {
private void adjustLightSensorRate(int lightSensorRate) {
// if the light sensor rate changed, update the sensor listener
if (lightSensorRate != mCurrentLightSensorRate) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "adjustLightSensorRate: " +
"previousRate=" + mCurrentLightSensorRate + ", " +
"currentRate=" + lightSensorRate);
@@ -527,7 +458,7 @@ class AutomaticBrightnessController {
}
private void setAmbientLux(float lux) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "setAmbientLux(" + lux + ")");
}
if (lux < 0) {
@@ -545,7 +476,7 @@ class AutomaticBrightnessController {
final float maxAmbientLux =
mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
}
@@ -559,7 +490,7 @@ class AutomaticBrightnessController {
}
private float calculateAmbientLux(long now, long horizon) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
}
final int N = mAmbientLightRingBuffer.size();
@@ -578,7 +509,7 @@ class AutomaticBrightnessController {
break;
}
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
mAmbientLightRingBuffer.getTime(endIndex) + ", " +
mAmbientLightRingBuffer.getLux(endIndex) + ")");
@@ -596,7 +527,7 @@ class AutomaticBrightnessController {
final long startTime = eventTime - now;
float weight = calculateWeight(startTime, endTime);
float lux = mAmbientLightRingBuffer.getLux(i);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
"lux=" + lux + ", " +
"weight=" + weight);
@@ -605,7 +536,7 @@ class AutomaticBrightnessController {
sum += lux * weight;
endTime = startTime;
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "calculateAmbientLux: " +
"totalWeight=" + totalWeight + ", " +
"newAmbientLux=" + (sum / totalWeight));
@@ -660,7 +591,7 @@ class AutomaticBrightnessController {
final long timeWhenSensorWarmedUp =
mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
if (time < timeWhenSensorWarmedUp) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " +
"time=" + time + ", " +
"timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
@@ -671,7 +602,7 @@ class AutomaticBrightnessController {
}
setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
mAmbientLuxValid = true;
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Initializing: " +
"mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
"mAmbientLux=" + mAmbientLux);
@@ -699,10 +630,10 @@ class AutomaticBrightnessController {
&& fastAmbientLux <= mAmbientDarkeningThreshold
&& nextDarkenTransition <= time)) {
setAmbientLux(fastAmbientLux);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: "
+ ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
- + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
+ + "mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold + ", "
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
+ "mAmbientLux=" + mAmbientLux);
}
@@ -719,7 +650,7 @@ class AutomaticBrightnessController {
// weighted ambient lux or not.
nextTransitionTime =
nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
}
@@ -731,8 +662,7 @@ class AutomaticBrightnessController {
return;
}
- float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
- mForegroundAppCategory);
+ float value = mBrightnessMapper.getBrightness(mAmbientLux);
int newScreenAutoBrightness =
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
@@ -743,7 +673,7 @@ class AutomaticBrightnessController {
if (mScreenAutoBrightness != -1
&& newScreenAutoBrightness > mScreenDarkeningThreshold
&& newScreenAutoBrightness < mScreenBrighteningThreshold) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "ignoring newScreenAutoBrightness: " + mScreenDarkeningThreshold
+ " < " + newScreenAutoBrightness + " < " + mScreenBrighteningThreshold);
}
@@ -751,7 +681,8 @@ class AutomaticBrightnessController {
}
if (mScreenAutoBrightness != newScreenAutoBrightness) {
- if (mLoggingEnabled) {
+
+ if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: " +
"mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
"newScreenAutoBrightness=" + newScreenAutoBrightness);
@@ -787,11 +718,18 @@ class AutomaticBrightnessController {
BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
}
+ private void cancelBrightnessAdjustmentSample() {
+ if (mBrightnessAdjustmentSamplePending) {
+ mBrightnessAdjustmentSamplePending = false;
+ mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
+ }
+ }
+
private void collectBrightnessAdjustmentSample() {
if (mBrightnessAdjustmentSamplePending) {
mBrightnessAdjustmentSamplePending = false;
if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
"lux=" + mAmbientLux + ", " +
"brightness=" + mScreenAutoBrightness + ", " +
@@ -807,68 +745,6 @@ class AutomaticBrightnessController {
}
}
- // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the
- // foreground app's package name and category and correct the brightness accordingly.
- private void registerForegroundAppUpdater() {
- try {
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- // This will not get called until the foreground app changes for the first time, so
- // call it explicitly to get the current foreground app's info.
- updateForegroundApp();
- } catch (RemoteException e) {
- // Nothing to do.
- }
- }
-
- private void unregisterForegroundAppUpdater() {
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- // Nothing to do.
- }
- mForegroundAppPackageName = null;
- mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
- }
-
- // Set the foreground app's package name and category, so brightness can be corrected per app.
- private void updateForegroundApp() {
- // The ActivityTaskManager's lock tends to get contended, so this is done in a background
- // thread and applied via this thread's handler synchronously.
- BackgroundThread.getHandler().post(new Runnable() {
- public void run() {
- try {
- // The foreground app is the top activity of the focused tasks stack.
- final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
- if (info == null || info.topActivity == null) {
- return;
- }
- final String packageName = info.topActivity.getPackageName();
- // If the app didn't change, there's nothing to do. Otherwise, we have to
- // update the category and re-apply the brightness correction.
- if (mForegroundAppPackageName != null
- && mForegroundAppPackageName.equals(packageName)) {
- return;
- }
- mPendingForegroundAppPackageName = packageName;
- ApplicationInfo app = mPackageManagerInternal.getApplicationInfo(packageName,
- 0 /* flags */, Process.SYSTEM_UID /* filterCallingUid */, mUserId);
- mPendingForegroundAppCategory = app.category;
- mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
- } catch (RemoteException e) {
- // Nothing to do.
- }
- }
- });
- }
-
- private void updateForegroundAppSync() {
- mForegroundAppPackageName = mPendingForegroundAppPackageName;
- mPendingForegroundAppPackageName = null;
- mForegroundAppCategory = mPendingForegroundAppCategory;
- mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
- updateAutoBrightness(true /* sendUpdate */);
- }
-
private final class AutomaticBrightnessHandler extends Handler {
public AutomaticBrightnessHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -888,14 +764,6 @@ class AutomaticBrightnessController {
case MSG_INVALIDATE_SHORT_TERM_MODEL:
invalidateShortTermModel();
break;
-
- case MSG_UPDATE_FOREGROUND_APP:
- updateForegroundApp();
- break;
-
- case MSG_UPDATE_FOREGROUND_APP_SYNC:
- updateForegroundAppSync();
- break;
}
}
}
@@ -916,15 +784,6 @@ class AutomaticBrightnessController {
}
};
- // Call back whenever the tasks stack changes, which includes tasks being created, removed, and
- // moving to top.
- class TaskStackListenerImpl extends TaskStackListener {
- @Override
- public void onTaskStackChanged() {
- mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP);
- }
- }
-
/** Callbacks to request updates to the display's power state. */
interface Callbacks {
void updateBrightness();
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 9fce644d6c4b..76c191d5e9ea 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -17,11 +17,9 @@
package com.android.server.display;
import android.annotation.Nullable;
-import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.display.BrightnessConfiguration;
-import android.hardware.display.BrightnessCorrection;
import android.os.PowerManager;
import android.util.MathUtils;
import android.util.Pair;
@@ -44,12 +42,11 @@ import java.util.Arrays;
*/
public abstract class BrightnessMappingStrategy {
private static final String TAG = "BrightnessMappingStrategy";
+ private static final boolean DEBUG = false;
private static final float LUX_GRAD_SMOOTHING = 0.25f;
private static final float MAX_GRAD = 1.0f;
- protected boolean mLoggingEnabled;
-
private static final Plog PLOG = Plog.createSystemPlog(TAG);
@Nullable
@@ -164,22 +161,6 @@ public abstract class BrightnessMappingStrategy {
}
/**
- * Enable/disable logging.
- *
- * @param loggingEnabled
- * Whether logging should be on/off.
- *
- * @return Whether the method succeeded or not.
- */
- public boolean setLoggingEnabled(boolean loggingEnabled) {
- if (mLoggingEnabled == loggingEnabled) {
- return false;
- }
- mLoggingEnabled = loggingEnabled;
- return true;
- }
-
- /**
* Sets the {@link BrightnessConfiguration}.
*
* @param config The new configuration. If {@code null} is passed, the default configuration is
@@ -189,33 +170,15 @@ public abstract class BrightnessMappingStrategy {
public abstract boolean setBrightnessConfiguration(@Nullable BrightnessConfiguration config);
/**
- * Returns the desired brightness of the display based on the current ambient lux, including
- * any context-related corrections.
- *
- * The returned brightness will be in the range [0, 1.0], where 1.0 is the display at max
- * brightness and 0 is the display at minimum brightness.
- *
- * @param lux The current ambient brightness in lux.
- * @param packageName the foreground app package name.
- * @param category the foreground app package category.
- * @return The desired brightness of the display normalized to the range [0, 1.0].
- */
- public abstract float getBrightness(float lux, String packageName,
- @ApplicationInfo.Category int category);
-
- /**
* Returns the desired brightness of the display based on the current ambient lux.
*
- * The returned brightness wil be in the range [0, 1.0], where 1.0 is the display at max
+ * The returned brightness will be in the range [0, 1.0], where 1.0 is the display at max
* brightness and 0 is the display at minimum brightness.
*
* @param lux The current ambient brightness in lux.
- *
* @return The desired brightness of the display normalized to the range [0, 1.0].
*/
- public float getBrightness(float lux) {
- return getBrightness(lux, null /* packageName */, ApplicationInfo.CATEGORY_UNDEFINED);
- }
+ public abstract float getBrightness(float lux);
/**
* Returns the current auto-brightness adjustment.
@@ -276,13 +239,13 @@ public abstract class BrightnessMappingStrategy {
public abstract void dump(PrintWriter pw);
- protected float normalizeAbsoluteBrightness(int brightness) {
+ private static float normalizeAbsoluteBrightness(int brightness) {
brightness = MathUtils.constrain(brightness,
PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
return (float) brightness / PowerManager.BRIGHTNESS_ON;
}
- private Pair<float[], float[]> insertControlPoint(
+ private static Pair<float[], float[]> insertControlPoint(
float[] luxLevels, float[] brightnessLevels, float lux, float brightness) {
final int idx = findInsertionPoint(luxLevels, lux);
final float[] newLuxLevels;
@@ -315,7 +278,7 @@ public abstract class BrightnessMappingStrategy {
* This assumes that {@code arr} is sorted. If all values in {@code arr} are greater
* than val, then it will return the length of arr as the insertion point.
*/
- private int findInsertionPoint(float[] arr, float val) {
+ private static int findInsertionPoint(float[] arr, float val) {
for (int i = 0; i < arr.length; i++) {
if (val <= arr[i]) {
return i;
@@ -324,8 +287,8 @@ public abstract class BrightnessMappingStrategy {
return arr.length;
}
- private void smoothCurve(float[] lux, float[] brightness, int idx) {
- if (mLoggingEnabled) {
+ private static void smoothCurve(float[] lux, float[] brightness, int idx) {
+ if (DEBUG) {
PLOG.logCurve("unsmoothed curve", lux, brightness);
}
float prevLux = lux[idx];
@@ -360,19 +323,19 @@ public abstract class BrightnessMappingStrategy {
prevBrightness = newBrightness;
brightness[i] = newBrightness;
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.logCurve("smoothed curve", lux, brightness);
}
}
- private float permissibleRatio(float currLux, float prevLux) {
+ private static float permissibleRatio(float currLux, float prevLux) {
return MathUtils.exp(MAX_GRAD
* (MathUtils.log(currLux + LUX_GRAD_SMOOTHING)
- MathUtils.log(prevLux + LUX_GRAD_SMOOTHING)));
}
- protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness,
- float currentBrightness) {
+ private static float inferAutoBrightnessAdjustment(float maxGamma,
+ float desiredBrightness, float currentBrightness) {
float adjustment = 0;
float gamma = Float.NaN;
// Extreme edge cases: use a simpler heuristic, as proper gamma correction around the edges
@@ -392,7 +355,7 @@ public abstract class BrightnessMappingStrategy {
adjustment = -MathUtils.log(gamma) / MathUtils.log(maxGamma);
}
adjustment = MathUtils.constrain(adjustment, -1, +1);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "inferAutoBrightnessAdjustment: " + maxGamma + "^" + -adjustment + "=" +
MathUtils.pow(maxGamma, -adjustment) + " == " + gamma);
Slog.d(TAG, "inferAutoBrightnessAdjustment: " + currentBrightness + "^" + gamma + "=" +
@@ -401,16 +364,16 @@ public abstract class BrightnessMappingStrategy {
return adjustment;
}
- protected Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness,
+ private static Pair<float[], float[]> getAdjustedCurve(float[] lux, float[] brightness,
float userLux, float userBrightness, float adjustment, float maxGamma) {
float[] newLux = lux;
float[] newBrightness = Arrays.copyOf(brightness, brightness.length);
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.logCurve("unadjusted curve", newLux, newBrightness);
}
adjustment = MathUtils.constrain(adjustment, -1, 1);
float gamma = MathUtils.pow(maxGamma, -adjustment);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "getAdjustedCurve: " + maxGamma + "^" + -adjustment + "=" +
MathUtils.pow(maxGamma, -adjustment) + " == " + gamma);
}
@@ -419,7 +382,7 @@ public abstract class BrightnessMappingStrategy {
newBrightness[i] = MathUtils.pow(newBrightness[i], gamma);
}
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.logCurve("gamma adjusted curve", newLux, newBrightness);
}
if (userLux != -1) {
@@ -427,7 +390,7 @@ public abstract class BrightnessMappingStrategy {
userBrightness);
newLux = curve.first;
newBrightness = curve.second;
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.logCurve("gamma and user adjusted curve", newLux, newBrightness);
// This is done for comparison.
curve = insertControlPoint(lux, brightness, userLux, userBrightness);
@@ -477,7 +440,7 @@ public abstract class BrightnessMappingStrategy {
mAutoBrightnessAdjustment = 0;
mUserLux = -1;
mUserBrightness = -1;
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.start("simple mapping strategy");
}
computeSpline();
@@ -489,8 +452,7 @@ public abstract class BrightnessMappingStrategy {
}
@Override
- public float getBrightness(float lux, String packageName,
- @ApplicationInfo.Category int category) {
+ public float getBrightness(float lux) {
return mSpline.interpolate(lux);
}
@@ -505,7 +467,7 @@ public abstract class BrightnessMappingStrategy {
if (adjustment == mAutoBrightnessAdjustment) {
return false;
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
adjustment);
PLOG.start("auto-brightness adjustment");
@@ -523,7 +485,7 @@ public abstract class BrightnessMappingStrategy {
@Override
public void addUserDataPoint(float lux, float brightness) {
float unadjustedBrightness = getUnadjustedBrightness(lux);
- if (mLoggingEnabled) {
+ if (DEBUG){
Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")");
PLOG.start("add user data point")
.logPoint("user data point", lux, brightness)
@@ -532,7 +494,7 @@ public abstract class BrightnessMappingStrategy {
float adjustment = inferAutoBrightnessAdjustment(mMaxGamma,
brightness /* desiredBrightness */,
unadjustedBrightness /* currentBrightness */);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " +
adjustment);
}
@@ -545,7 +507,7 @@ public abstract class BrightnessMappingStrategy {
@Override
public void clearUserDataPoints() {
if (mUserLux != -1) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0");
PLOG.start("clear user data points")
.logPoint("user data point", mUserLux, mUserBrightness);
@@ -652,7 +614,7 @@ public abstract class BrightnessMappingStrategy {
mBacklightToNitsSpline = Spline.createSpline(normalizedBacklight, nits);
mDefaultConfig = config;
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.start("physical mapping strategy");
}
mConfig = config;
@@ -667,7 +629,7 @@ public abstract class BrightnessMappingStrategy {
if (config.equals(mConfig)) {
return false;
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
PLOG.start("brightness configuration");
}
mConfig = config;
@@ -676,17 +638,9 @@ public abstract class BrightnessMappingStrategy {
}
@Override
- public float getBrightness(float lux, String packageName,
- @ApplicationInfo.Category int category) {
+ public float getBrightness(float lux) {
float nits = mBrightnessSpline.interpolate(lux);
float backlight = mNitsToBacklightSpline.interpolate(nits);
- // Correct the brightness according to the current application and its category, but
- // only if no user data point is set (as this will oevrride the user setting).
- if (mUserLux == -1) {
- backlight = correctBrightness(backlight, packageName, category);
- } else if (mLoggingEnabled) {
- Slog.d(TAG, "user point set, correction not applied");
- }
return backlight;
}
@@ -701,7 +655,7 @@ public abstract class BrightnessMappingStrategy {
if (adjustment == mAutoBrightnessAdjustment) {
return false;
}
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "setAutoBrightnessAdjustment: " + mAutoBrightnessAdjustment + " => " +
adjustment);
PLOG.start("auto-brightness adjustment");
@@ -719,7 +673,7 @@ public abstract class BrightnessMappingStrategy {
@Override
public void addUserDataPoint(float lux, float brightness) {
float unadjustedBrightness = getUnadjustedBrightness(lux);
- if (mLoggingEnabled) {
+ if (DEBUG){
Slog.d(TAG, "addUserDataPoint: (" + lux + "," + brightness + ")");
PLOG.start("add user data point")
.logPoint("user data point", lux, brightness)
@@ -728,7 +682,7 @@ public abstract class BrightnessMappingStrategy {
float adjustment = inferAutoBrightnessAdjustment(mMaxGamma,
brightness /* desiredBrightness */,
unadjustedBrightness /* currentBrightness */);
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "addUserDataPoint: " + mAutoBrightnessAdjustment + " => " +
adjustment);
}
@@ -741,7 +695,7 @@ public abstract class BrightnessMappingStrategy {
@Override
public void clearUserDataPoints() {
if (mUserLux != -1) {
- if (mLoggingEnabled) {
+ if (DEBUG) {
Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0");
PLOG.start("clear user data points")
.logPoint("user data point", mUserLux, mUserBrightness);
@@ -804,21 +758,5 @@ public abstract class BrightnessMappingStrategy {
Spline spline = Spline.createSpline(curve.first, curve.second);
return mNitsToBacklightSpline.interpolate(spline.interpolate(lux));
}
-
- private float correctBrightness(float brightness, String packageName, int category) {
- if (packageName != null) {
- BrightnessCorrection correction = mConfig.getCorrectionByPackageName(packageName);
- if (correction != null) {
- return correction.apply(brightness);
- }
- }
- if (category != ApplicationInfo.CATEGORY_UNDEFINED) {
- BrightnessCorrection correction = mConfig.getCorrectionByCategory(category);
- if (correction != null) {
- return correction.apply(brightness);
- }
- }
- return brightness;
- }
}
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b6c82d3a66e4..73d3d9591529 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
import android.animation.Animator;
@@ -31,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.hardware.display.ColorDisplayManager;
import android.hardware.display.IColorDisplayManager;
import android.net.Uri;
import android.opengl.Matrix;
@@ -86,11 +88,80 @@ public final class ColorDisplayService extends SystemService {
*/
private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
- private final Handler mHandler;
+ private final TintController mNightDisplayTintController = new TintController() {
+
+ private float[] mMatrixNightDisplay = new float[16];
+ private final float[] mColorTempCoefficients = new float[9];
+
+ /**
+ * Set coefficients based on whether the color matrix is linear or not.
+ */
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ final String[] coefficients = context.getResources().getStringArray(needsLinear
+ ? R.array.config_nightDisplayColorTemperatureCoefficients
+ : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
+ for (int i = 0; i < 9 && i < coefficients.length; i++) {
+ mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
+ }
+ }
+
+ @Override
+ public void setMatrix(int cct) {
+ if (mMatrixNightDisplay.length != 16) {
+ Slog.d(TAG, "The display transformation matrix must be 4x4");
+ return;
+ }
+
+ Matrix.setIdentityM(mMatrixNightDisplay, 0);
+
+ final float squareTemperature = cct * cct;
+ final float red = squareTemperature * mColorTempCoefficients[0]
+ + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
+ final float green = squareTemperature * mColorTempCoefficients[3]
+ + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
+ final float blue = squareTemperature * mColorTempCoefficients[6]
+ + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
+ mMatrixNightDisplay[0] = red;
+ mMatrixNightDisplay[5] = green;
+ mMatrixNightDisplay[10] = blue;
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return isActivated() ? mMatrixNightDisplay : MATRIX_IDENTITY;
+ }
+
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+ }
+ };
+
+ private final TintController mDisplayWhiteBalanceTintController = new TintController() {
+
+ private float[] mMatrixDisplayWhiteBalance = new float[16];
+
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+ }
+
+ @Override
+ public void setMatrix(int cct) {
+ }
- private float[] mMatrixNight = new float[16];
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+ }
+ };
- private final float[] mColorTempCoefficients = new float[9];
+ private final Handler mHandler;
private int mCurrentUser = UserHandle.USER_NULL;
private ContentObserver mUserSetupObserver;
@@ -98,11 +169,13 @@ public final class ColorDisplayService extends SystemService {
private ColorDisplayController mNightDisplayController;
private ContentObserver mContentObserver;
- private ValueAnimator mColorMatrixAnimator;
- private Boolean mIsNightDisplayActivated;
+ private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
+
private NightDisplayAutoMode mNightDisplayAutoMode;
+ private Integer mDisplayWhiteBalanceColorTemperature;
+
public ColorDisplayService(Context context) {
super(context);
mHandler = new Handler(Looper.getMainLooper());
@@ -111,6 +184,7 @@ public final class ColorDisplayService extends SystemService {
@Override
public void onStart() {
publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
+ publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal());
}
@Override
@@ -232,6 +306,9 @@ public final class ColorDisplayService extends SystemService {
case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
onAccessibilityTransformChanged();
break;
+ case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
+ onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+ break;
}
}
}
@@ -256,25 +333,41 @@ public final class ColorDisplayService extends SystemService {
cr.registerContentObserver(
Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+ cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
+ false /* notifyForDescendants */, mContentObserver, mCurrentUser);
// Set the color mode, if valid, and immediately apply the updated tint matrix based on the
// existing activated state. This ensures consistency of tint across the color mode change.
onDisplayColorModeChanged(mNightDisplayController.getColorMode());
- // Reset the activated state.
- mIsNightDisplayActivated = null;
+ if (ColorDisplayManager.isNightDisplayAvailable(getContext())) {
+ // Reset the activated state.
+ mNightDisplayTintController.setActivated(null);
+
+ // Prepare the night display color transformation matrix.
+ mNightDisplayTintController
+ .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+ mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
- setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+ // Initialize the current auto mode.
+ onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
- // Prepare color transformation matrix.
- setMatrix(mNightDisplayController.getColorTemperature(), mMatrixNight);
+ // Force the initialization current activated state.
+ if (mNightDisplayTintController.isActivatedStateNotSet()) {
+ onNightDisplayActivated(mNightDisplayController.isActivated());
+ }
+ }
- // Initialize the current auto mode.
- onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
+ if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+ // Prepare the display white balance transform matrix.
+ mDisplayWhiteBalanceTintController
+ .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+ if (mDisplayWhiteBalanceColorTemperature != null) {
+ mDisplayWhiteBalanceTintController
+ .setMatrix(mDisplayWhiteBalanceColorTemperature);
+ }
- // Force the initialization current activated state.
- if (mIsNightDisplayActivated == null) {
- onNightDisplayActivated(mNightDisplayController.isActivated());
+ onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
}
}
@@ -287,28 +380,31 @@ public final class ColorDisplayService extends SystemService {
mNightDisplayController = null;
}
- if (mNightDisplayAutoMode != null) {
- mNightDisplayAutoMode.onStop();
- mNightDisplayAutoMode = null;
+ if (ColorDisplayManager.isNightDisplayAvailable(getContext())) {
+ if (mNightDisplayAutoMode != null) {
+ mNightDisplayAutoMode.onStop();
+ mNightDisplayAutoMode = null;
+ }
+ mNightDisplayTintController.endAnimator();
}
- if (mColorMatrixAnimator != null) {
- mColorMatrixAnimator.end();
- mColorMatrixAnimator = null;
+ if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+ mDisplayWhiteBalanceTintController.endAnimator();
}
}
private void onNightDisplayActivated(boolean activated) {
- if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activated) {
+ if (mNightDisplayTintController.isActivatedStateNotSet()
+ || mNightDisplayTintController.isActivated() != activated) {
Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
- mIsNightDisplayActivated = activated;
+ mNightDisplayTintController.setActivated(activated);
if (mNightDisplayAutoMode != null) {
mNightDisplayAutoMode.onActivated(activated);
}
- applyTint(false);
+ applyTint(mNightDisplayTintController, false);
}
}
@@ -348,8 +444,8 @@ public final class ColorDisplayService extends SystemService {
}
private void onNightDisplayColorTemperatureChanged(int colorTemperature) {
- setMatrix(colorTemperature, mMatrixNight);
- applyTint(true);
+ mNightDisplayTintController.setMatrix(colorTemperature);
+ applyTint(mNightDisplayTintController, true);
}
private void onDisplayColorModeChanged(int mode) {
@@ -357,66 +453,53 @@ public final class ColorDisplayService extends SystemService {
return;
}
- // Cancel the night display tint animator if it's running.
- if (mColorMatrixAnimator != null) {
- mColorMatrixAnimator.cancel();
- }
+ mNightDisplayTintController.cancelAnimator();
+ mDisplayWhiteBalanceTintController.cancelAnimator();
+
+ mNightDisplayTintController
+ .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
+ mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
- setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
- setMatrix(mNightDisplayController.getColorTemperature(), mMatrixNight);
+ mDisplayWhiteBalanceTintController
+ .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
+ if (mDisplayWhiteBalanceColorTemperature != null) {
+ mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
+ }
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
- dtm.setColorMode(mode, (mIsNightDisplayActivated != null && mIsNightDisplayActivated)
- ? mMatrixNight : MATRIX_IDENTITY);
+ dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
}
private void onAccessibilityTransformChanged() {
onDisplayColorModeChanged(mNightDisplayController.getColorMode());
}
- /**
- * Set coefficients based on whether the color matrix is linear or not.
- */
- private void setCoefficientMatrix(Context context, boolean needsLinear) {
- final String[] coefficients = context.getResources().getStringArray(needsLinear
- ? R.array.config_nightDisplayColorTemperatureCoefficients
- : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
- for (int i = 0; i < 9 && i < coefficients.length; i++) {
- mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
- }
- }
/**
* Applies current color temperature matrix, or removes it if deactivated.
*
* @param immediate {@code true} skips transition animation
*/
- private void applyTint(boolean immediate) {
- // Cancel the old animator if still running.
- if (mColorMatrixAnimator != null) {
- mColorMatrixAnimator.cancel();
- }
+ private void applyTint(TintController tintController, boolean immediate) {
+ tintController.cancelAnimator();
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
- final float[] from = dtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
- final float[] to = mIsNightDisplayActivated ? mMatrixNight : MATRIX_IDENTITY;
+ final float[] from = dtm.getColorMatrix(tintController.getLevel());
+ final float[] to = tintController.getMatrix();
if (immediate) {
- dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to);
+ dtm.setColorMatrix(tintController.getLevel(), to);
} else {
- mColorMatrixAnimator = ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
- from == null ? MATRIX_IDENTITY : from, to);
- mColorMatrixAnimator.setDuration(TRANSITION_DURATION);
- mColorMatrixAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+ tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
+ from == null ? MATRIX_IDENTITY : from, to));
+ tintController.getAnimator().setDuration(TRANSITION_DURATION);
+ tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
getContext(), android.R.interpolator.fast_out_slow_in));
- mColorMatrixAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animator) {
- final float[] value = (float[]) animator.getAnimatedValue();
- dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, value);
- }
+ tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
+ final float[] value = (float[]) animator.getAnimatedValue();
+ dtm.setColorMatrix(tintController.getLevel(), value);
});
- mColorMatrixAnimator.addListener(new AnimatorListenerAdapter() {
+ tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
private boolean mIsCancelled;
@@ -431,42 +514,16 @@ public final class ColorDisplayService extends SystemService {
// Ensure final color matrix is set at the end of the animation. If the
// animation is cancelled then don't set the final color matrix so the new
// animator can pick up from where this one left off.
- dtm.setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, to);
+ dtm.setColorMatrix(tintController.getLevel(), to);
}
- mColorMatrixAnimator = null;
+ tintController.setAnimator(null);
}
});
- mColorMatrixAnimator.start();
+ tintController.getAnimator().start();
}
}
/**
- * Set the color transformation {@code MATRIX_NIGHT} to the given color temperature.
- *
- * @param colorTemperature color temperature in Kelvin
- * @param outTemp the 4x4 display transformation matrix for that color temperature
- */
- private void setMatrix(int colorTemperature, float[] outTemp) {
- if (outTemp.length != 16) {
- Slog.d(TAG, "The display transformation matrix must be 4x4");
- return;
- }
-
- Matrix.setIdentityM(mMatrixNight, 0);
-
- final float squareTemperature = colorTemperature * colorTemperature;
- final float red = squareTemperature * mColorTempCoefficients[0]
- + colorTemperature * mColorTempCoefficients[1] + mColorTempCoefficients[2];
- final float green = squareTemperature * mColorTempCoefficients[3]
- + colorTemperature * mColorTempCoefficients[4] + mColorTempCoefficients[5];
- final float blue = squareTemperature * mColorTempCoefficients[6]
- + colorTemperature * mColorTempCoefficients[7] + mColorTempCoefficients[8];
- outTemp[0] = red;
- outTemp[5] = green;
- outTemp[10] = blue;
- }
-
- /**
* Returns the first date time corresponding to the local time that occurs before the provided
* date time.
*
@@ -498,6 +555,18 @@ public final class ColorDisplayService extends SystemService {
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
+ private void onDisplayWhiteBalanceEnabled(boolean enabled) {
+ mDisplayWhiteBalanceTintController.setActivated(enabled);
+ if (mDisplayWhiteBalanceListener != null) {
+ mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+ }
+ }
+
+ private boolean isDisplayWhiteBalanceSettingEnabled() {
+ return Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.DISPLAY_WHITE_BALANCE_ENABLED, 0, mCurrentUser) == 1;
+ }
+
private boolean isDeviceColorManagedInternal() {
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
return dtm.isDeviceColorManaged();
@@ -507,7 +576,7 @@ public final class ColorDisplayService extends SystemService {
* Returns the last time the night display transform activation state was changed, or {@link
* LocalDateTime#MIN} if night display has never been activated.
*/
- private @NonNull LocalDateTime getNightDisplayLastActivatedTimeSetting() {
+ private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
final ContentResolver cr = getContext().getContentResolver();
final String lastActivatedTime = Secure.getStringForUser(
cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
@@ -577,11 +646,12 @@ public final class ColorDisplayService extends SystemService {
}
}
- if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activate) {
+ if (mNightDisplayTintController.isActivatedStateNotSet() || (
+ mNightDisplayTintController.isActivated() != activate)) {
mNightDisplayController.setActivated(activate);
}
- updateNextAlarm(mIsNightDisplayActivated, now);
+ updateNextAlarm(mNightDisplayTintController.isActivated(), now);
}
private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
@@ -672,7 +742,8 @@ public final class ColorDisplayService extends SystemService {
}
}
- if (mIsNightDisplayActivated == null || mIsNightDisplayActivated != activate) {
+ if (mNightDisplayTintController.isActivatedStateNotSet() || (
+ mNightDisplayTintController.isActivated() != activate)) {
mNightDisplayController.setActivated(activate);
}
}
@@ -724,6 +795,115 @@ public final class ColorDisplayService extends SystemService {
}
}
+ private abstract static class TintController {
+
+ private ValueAnimator mAnimator;
+ private Boolean mIsActivated;
+
+ public ValueAnimator getAnimator() {
+ return mAnimator;
+ }
+
+ public void setAnimator(ValueAnimator animator) {
+ mAnimator = animator;
+ }
+
+ /**
+ * Cancel the animator if it's still running.
+ */
+ public void cancelAnimator() {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ }
+
+ /**
+ * End the animator if it's still running, jumping to the end state.
+ */
+ public void endAnimator() {
+ if (mAnimator != null) {
+ mAnimator.end();
+ mAnimator = null;
+ }
+ }
+
+ public void setActivated(Boolean isActivated) {
+ mIsActivated = isActivated;
+ }
+
+ public boolean isActivated() {
+ return mIsActivated != null && mIsActivated;
+ }
+
+ public boolean isActivatedStateNotSet() {
+ return mIsActivated == null;
+ }
+
+ /**
+ * Set up any constants needed for computing the matrix.
+ */
+ public abstract void setUp(Context context, boolean needsLinear);
+
+ /**
+ * Sets the 4x4 matrix to apply.
+ */
+ public abstract void setMatrix(int value);
+
+ /**
+ * Get the 4x4 matrix to apply.
+ */
+ public abstract float[] getMatrix();
+
+ /**
+ * Get the color transform level to apply the matrix.
+ */
+ public abstract int getLevel();
+ }
+
+ /**
+ * Local service that allows color transforms to be enabled from other system services.
+ */
+ public final class ColorDisplayServiceInternal {
+
+ /**
+ * Set the current CCT value for the display white balance transform, and if the transform
+ * is enabled, apply it.
+ *
+ * @param cct the color temperature in Kelvin.
+ */
+ public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
+ // Update the transform matrix even if it can't be applied.
+ mDisplayWhiteBalanceColorTemperature = cct;
+ mDisplayWhiteBalanceTintController.setMatrix(cct);
+
+ if (mDisplayWhiteBalanceTintController.isActivated()) {
+ applyTint(mDisplayWhiteBalanceTintController, true);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets the listener and returns whether display white balance is currently enabled.
+ */
+ public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
+ mDisplayWhiteBalanceListener = listener;
+ return mDisplayWhiteBalanceTintController.isActivated();
+ }
+ }
+
+ /**
+ * Listener for changes in display white balance status.
+ */
+ public interface DisplayWhiteBalanceListener {
+
+ /**
+ * Notify that the display white balance status has changed, either due to preemption by
+ * another transform or the feature being turned off.
+ */
+ void onDisplayWhiteBalanceStatusChanged(boolean enabled);
+ }
+
private final class BinderService extends IColorDisplayManager.Stub {
@Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b1ba05c035b3..0a1a9a20e0da 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2144,14 +2144,6 @@ public final class DisplayManagerService extends SystemService {
mContext.getPackageName());
}
- void setAutoBrightnessLoggingEnabled(boolean enabled) {
- if (mDisplayPowerController != null) {
- synchronized (mSyncRoot) {
- mDisplayPowerController.setAutoBrightnessLoggingEnabled(enabled);
- }
- }
- }
-
private boolean validatePackageName(int uid, String packageName) {
if (packageName != null) {
String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index abbfc7b18f94..27cad1eece09 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -17,9 +17,14 @@
package com.android.server.display;
import android.content.Intent;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.util.Slog;
import java.io.PrintWriter;
+import java.lang.NumberFormatException;
class DisplayManagerShellCommand extends ShellCommand {
private static final String TAG = "DisplayManagerShellCommand";
@@ -41,10 +46,6 @@ class DisplayManagerShellCommand extends ShellCommand {
return setBrightness();
case "reset-brightness-configuration":
return resetBrightnessConfiguration();
- case "ab-logging-enable":
- return setAutoBrightnessLoggingEnabled(true);
- case "ab-logging-disable":
- return setAutoBrightnessLoggingEnabled(false);
default:
return handleDefaultCommands(cmd);
}
@@ -61,10 +62,6 @@ class DisplayManagerShellCommand extends ShellCommand {
pw.println(" Sets the current brightness to BRIGHTNESS (a number between 0 and 1).");
pw.println(" reset-brightness-configuration");
pw.println(" Reset the brightness to its default configuration.");
- pw.println(" ab-logging-enable");
- pw.println(" Enable auto-brightness logging.");
- pw.println(" ab-logging-disable");
- pw.println(" Disable auto-brightness logging.");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
@@ -92,9 +89,4 @@ class DisplayManagerShellCommand extends ShellCommand {
mService.resetBrightnessConfiguration();
return 0;
}
-
- private int setAutoBrightnessLoggingEnabled(boolean enabled) {
- mService.setAutoBrightnessLoggingEnabled(enabled);
- return 0;
- }
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c9ed9f7cea43..249270bfda7e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -523,9 +523,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
public void onSwitchUser(@UserIdInt int newUserId) {
handleSettingsChange(true /* userSwitch */);
mBrightnessTracker.onSwitchUser(newUserId);
- if (mAutomaticBrightnessController != null) {
- mAutomaticBrightnessController.onSwitchUser(newUserId);
- }
}
public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(
@@ -1839,10 +1836,4 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mHandler.sendMessage(msg);
}
}
-
- void setAutoBrightnessLoggingEnabled(boolean enabled) {
- if (mAutomaticBrightnessController != null) {
- mAutomaticBrightnessController.setLoggingEnabled(enabled);
- }
- }
}
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 4ad26dae8380..a5e9728e4b68 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -45,6 +45,10 @@ public class DisplayTransformManager {
*/
public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
/**
+ * Color transform level used by display white balance to adjust the display's white point.
+ */
+ public static final int LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE = 125;
+ /**
* Color transform level used to adjust the color saturation of the display.
*/
public static final int LEVEL_COLOR_MATRIX_SATURATION = 150;
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 9aec43b6eaed..89cef621a55d 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -16,6 +16,13 @@
package com.android.server.display;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import android.annotation.Nullable;
import android.graphics.Point;
import android.hardware.display.BrightnessConfiguration;
@@ -23,20 +30,13 @@ import android.hardware.display.WifiDisplay;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.Pair;
import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.Xml;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
-
-import libcore.io.IoUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -50,9 +50,12 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
+import libcore.io.IoUtils;
+
/**
* Manages persistent state recorded by the display manager service as an XML file.
* Caller must acquire lock on the data store before accessing it.
@@ -107,9 +110,14 @@ final class PersistentDataStore {
private static final String TAG_BRIGHTNESS_CONFIGURATIONS = "brightness-configurations";
private static final String TAG_BRIGHTNESS_CONFIGURATION = "brightness-configuration";
+ private static final String TAG_BRIGHTNESS_CURVE = "brightness-curve";
+ private static final String TAG_BRIGHTNESS_POINT = "brightness-point";
private static final String ATTR_USER_SERIAL = "user-serial";
private static final String ATTR_PACKAGE_NAME = "package-name";
private static final String ATTR_TIME_STAMP = "timestamp";
+ private static final String ATTR_LUX = "lux";
+ private static final String ATTR_NITS = "nits";
+ private static final String ATTR_DESCRIPTION = "description";
// Remembered Wifi display devices.
private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
@@ -638,8 +646,7 @@ final class PersistentDataStore {
}
try {
- BrightnessConfiguration config =
- BrightnessConfiguration.loadFromXml(parser);
+ BrightnessConfiguration config = loadConfigurationFromXml(parser);
if (userSerial >= 0 && config != null) {
mConfigurations.put(userSerial, config);
if (timeStamp != -1) {
@@ -656,6 +663,56 @@ final class PersistentDataStore {
}
}
+ private static BrightnessConfiguration loadConfigurationFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ String description = null;
+ Pair<float[], float[]> curve = null;
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_BRIGHTNESS_CURVE.equals(parser.getName())) {
+ description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
+ curve = loadCurveFromXml(parser);
+ }
+ }
+ if (curve == null) {
+ return null;
+ }
+ final BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
+ curve.first, curve.second);
+ builder.setDescription(description);
+ return builder.build();
+ }
+
+ private static Pair<float[], float[]> loadCurveFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ List<Float> luxLevels = new ArrayList<>();
+ List<Float> nitLevels = new ArrayList<>();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (TAG_BRIGHTNESS_POINT.equals(parser.getName())) {
+ luxLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_LUX)));
+ nitLevels.add(loadFloat(parser.getAttributeValue(null, ATTR_NITS)));
+ }
+ }
+ final int N = luxLevels.size();
+ float[] lux = new float[N];
+ float[] nits = new float[N];
+ for (int i = 0; i < N; i++) {
+ lux[i] = luxLevels.get(i);
+ nits[i] = nitLevels.get(i);
+ }
+ return Pair.create(lux, nits);
+ }
+
+ private static float loadFloat(String val) {
+ try {
+ return Float.parseFloat(val);
+ } catch (NullPointerException | NumberFormatException e) {
+ Slog.e(TAG, "Failed to parse float loading brightness config", e);
+ return Float.NEGATIVE_INFINITY;
+ }
+ }
+
public void saveToXml(XmlSerializer serializer) throws IOException {
for (int i = 0; i < mConfigurations.size(); i++) {
final int userSerial = mConfigurations.keyAt(i);
@@ -671,11 +728,27 @@ final class PersistentDataStore {
if (timestamp != -1) {
serializer.attribute(null, ATTR_TIME_STAMP, Long.toString(timestamp));
}
- config.saveToXml(serializer);
+ saveConfigurationToXml(serializer, config);
serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION);
}
}
+ private static void saveConfigurationToXml(XmlSerializer serializer,
+ BrightnessConfiguration config) throws IOException {
+ serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
+ if (config.getDescription() != null) {
+ serializer.attribute(null, ATTR_DESCRIPTION, config.getDescription());
+ }
+ final Pair<float[], float[]> curve = config.getCurve();
+ for (int i = 0; i < curve.first.length; i++) {
+ serializer.startTag(null, TAG_BRIGHTNESS_POINT);
+ serializer.attribute(null, ATTR_LUX, Float.toString(curve.first[i]));
+ serializer.attribute(null, ATTR_NITS, Float.toString(curve.second[i]));
+ serializer.endTag(null, TAG_BRIGHTNESS_POINT);
+ }
+ serializer.endTag(null, TAG_BRIGHTNESS_CURVE);
+ }
+
public void dump(final PrintWriter pw, final String prefix) {
for (int i = 0; i < mConfigurations.size(); i++) {
final int userSerial = mConfigurations.keyAt(i);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index d154830062f6..1f0f94a7bf0b 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -18,6 +18,7 @@ package com.android.server.hdmi;
import android.annotation.IntDef;
import android.hardware.hdmi.HdmiDeviceInfo;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -316,7 +317,7 @@ final class Constants {
* <p>When ARC is initiated, this port will be used to turn on ARC.
*/
static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
- "persist.sys.hdmi.property_sytem_audio_device_arc_port";
+ "persist.sys.hdmi.property_sytem_audio_device_arc_port";
/**
* Property to strip local audio of amplifier and use local speaker
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 3845954bc0d4..9690ba877c1e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -95,6 +95,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
startQueuedActions();
}
+ @Override
+ protected int findKeyReceiverAddress() {
+ return Constants.ADDR_TV;
+ }
+
@VisibleForTesting
protected void systemAudioControlOnPowerOn(
int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f468c0bf6652..3420b263eac5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,6 +18,7 @@ package com.android.server.hdmi;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
+
import static com.android.server.hdmi.Constants.DISABLED;
import static com.android.server.hdmi.Constants.ENABLED;
import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
@@ -67,6 +68,7 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
@@ -76,6 +78,9 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
+
+import libcore.util.EmptyArray;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -85,7 +90,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import libcore.util.EmptyArray;
/**
* Provides a service for sending and processing HDMI control messages,
@@ -1469,12 +1473,12 @@ public class HdmiControlService extends SystemService {
@Override
public boolean getSystemAudioMode() {
+ // TODO(shubang): handle getSystemAudioMode() for all device types
enforceAccessPermission();
HdmiCecLocalDeviceTv tv = tv();
- if (tv == null) {
- return false;
- }
- return tv.isSystemAudioActivated();
+ HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+ return (tv != null && tv.isSystemAudioActivated())
+ || (audioSystem != null && audioSystem.isSystemAudioActivated());
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
new file mode 100644
index 000000000000..f79ac164ef55
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class to read/write subtype.xml.
+ */
+final class AdditionalSubtypeUtils {
+ private static final String TAG = "AdditionalSubtypeUtils";
+
+ private static final String SYSTEM_PATH = "system";
+ private static final String INPUT_METHOD_PATH = "inputmethod";
+ private static final String ADDITIONAL_SUBTYPES_FILE_NAME = "subtypes.xml";
+ private static final String NODE_SUBTYPES = "subtypes";
+ private static final String NODE_SUBTYPE = "subtype";
+ private static final String NODE_IMI = "imi";
+ private static final String ATTR_ID = "id";
+ private static final String ATTR_LABEL = "label";
+ private static final String ATTR_ICON = "icon";
+ private static final String ATTR_IME_SUBTYPE_ID = "subtypeId";
+ private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale";
+ private static final String ATTR_IME_SUBTYPE_LANGUAGE_TAG = "languageTag";
+ private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
+ private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
+ private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
+ private static final String ATTR_IS_ASCII_CAPABLE = "isAsciiCapable";
+
+ private AdditionalSubtypeUtils() {
+ }
+
+ /**
+ * Returns a {@link File} that represents the directory at which subtype.xml will be placed.
+ *
+ * @param userId User ID with with subtype.xml path should be determined.
+ * @return {@link File} that represents the directory.
+ */
+ @NonNull
+ private static File getInputMethodDir(@UserIdInt int userId) {
+ final File systemDir = userId == UserHandle.USER_SYSTEM
+ ? new File(Environment.getDataDirectory(), SYSTEM_PATH)
+ : Environment.getUserSystemDirectory(userId);
+ return new File(systemDir, INPUT_METHOD_PATH);
+ }
+
+ /**
+ * Returns an {@link AtomicFile} to read/write additional subtype for the given user id.
+ *
+ * @param inputMethodDir Directory at which subtype.xml will be placed
+ * @return {@link AtomicFile} to be used to read/write additional subtype
+ */
+ @NonNull
+ private static AtomicFile getAdditionalSubtypeFile(File inputMethodDir) {
+ final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
+ return new AtomicFile(subtypeFile, "input-subtypes");
+ }
+
+ /**
+ * Write additional subtypes into "subtype.xml".
+ *
+ * <p>This method does not confer any data/file locking semantics. Caller must make sure that
+ * multiple threads are not calling this method at the same time for the same {@code userId}.
+ * </p>
+ *
+ * @param allSubtypes {@link ArrayMap} from IME ID to additional subtype list. Passing an empty
+ * map deletes the file.
+ * @param methodMap {@link ArrayMap} from IME ID to {@link InputMethodInfo}.
+ * @param userId The user ID to be associated with.
+ */
+ static void save(ArrayMap<String, List<InputMethodSubtype>> allSubtypes,
+ ArrayMap<String, InputMethodInfo> methodMap, @UserIdInt int userId) {
+ final File inputMethodDir = getInputMethodDir(userId);
+
+ if (allSubtypes.isEmpty()) {
+ if (!inputMethodDir.exists()) {
+ // Even the parent directory doesn't exist. There is nothing to clean up.
+ return;
+ }
+ final AtomicFile subtypesFile = getAdditionalSubtypeFile(inputMethodDir);
+ if (subtypesFile.exists()) {
+ subtypesFile.delete();
+ }
+ if (FileUtils.listFilesOrEmpty(inputMethodDir).length == 0) {
+ if (!inputMethodDir.delete()) {
+ Slog.e(TAG, "Failed to delete the empty parent directory " + inputMethodDir);
+ }
+ }
+ return;
+ }
+
+ if (!inputMethodDir.exists() && !inputMethodDir.mkdirs()) {
+ Slog.e(TAG, "Failed to create a parent directory " + inputMethodDir);
+ return;
+ }
+
+ // Safety net for the case that this function is called before methodMap is set.
+ final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
+ FileOutputStream fos = null;
+ final AtomicFile subtypesFile = getAdditionalSubtypeFile(inputMethodDir);
+ try {
+ fos = subtypesFile.startWrite();
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ out.startTag(null, NODE_SUBTYPES);
+ for (String imiId : allSubtypes.keySet()) {
+ if (isSetMethodMap && !methodMap.containsKey(imiId)) {
+ Slog.w(TAG, "IME uninstalled or not valid.: " + imiId);
+ continue;
+ }
+ out.startTag(null, NODE_IMI);
+ out.attribute(null, ATTR_ID, imiId);
+ final List<InputMethodSubtype> subtypesList = allSubtypes.get(imiId);
+ final int numSubtypes = subtypesList.size();
+ for (int i = 0; i < numSubtypes; ++i) {
+ final InputMethodSubtype subtype = subtypesList.get(i);
+ out.startTag(null, NODE_SUBTYPE);
+ if (subtype.hasSubtypeId()) {
+ out.attribute(null, ATTR_IME_SUBTYPE_ID,
+ String.valueOf(subtype.getSubtypeId()));
+ }
+ out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
+ out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
+ out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
+ out.attribute(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG,
+ subtype.getLanguageTag());
+ out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
+ out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
+ out.attribute(null, ATTR_IS_AUXILIARY,
+ String.valueOf(subtype.isAuxiliary() ? 1 : 0));
+ out.attribute(null, ATTR_IS_ASCII_CAPABLE,
+ String.valueOf(subtype.isAsciiCapable() ? 1 : 0));
+ out.endTag(null, NODE_SUBTYPE);
+ }
+ out.endTag(null, NODE_IMI);
+ }
+ out.endTag(null, NODE_SUBTYPES);
+ out.endDocument();
+ subtypesFile.finishWrite(fos);
+ } catch (java.io.IOException e) {
+ Slog.w(TAG, "Error writing subtypes", e);
+ if (fos != null) {
+ subtypesFile.failWrite(fos);
+ }
+ }
+ }
+
+ /**
+ * Read additional subtypes from "subtype.xml".
+ *
+ * <p>This method does not confer any data/file locking semantics. Caller must make sure that
+ * multiple threads are not calling this method at the same time for the same {@code userId}.
+ * </p>
+ *
+ * @param allSubtypes {@link ArrayMap} from IME ID to additional subtype list. This parameter
+ * will be used to return the result.
+ * @param userId The user ID to be associated with.
+ */
+ static void load(@NonNull ArrayMap<String, List<InputMethodSubtype>> allSubtypes,
+ @UserIdInt int userId) {
+ allSubtypes.clear();
+
+ final AtomicFile subtypesFile = getAdditionalSubtypeFile(getInputMethodDir(userId));
+ if (!subtypesFile.exists()) {
+ // Not having the file means there is no additional subtype.
+ return;
+ }
+ try (FileInputStream fis = subtypesFile.openRead()) {
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, StandardCharsets.UTF_8.name());
+ int type = parser.getEventType();
+ // Skip parsing until START_TAG
+ while (true) {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG || type == XmlPullParser.END_DOCUMENT) {
+ break;
+ }
+ }
+ String firstNodeName = parser.getName();
+ if (!NODE_SUBTYPES.equals(firstNodeName)) {
+ throw new XmlPullParserException("Xml doesn't start with subtypes");
+ }
+ final int depth = parser.getDepth();
+ String currentImiId = null;
+ ArrayList<InputMethodSubtype> tempSubtypesArray = null;
+ while (((type = parser.next()) != XmlPullParser.END_TAG
+ || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final String nodeName = parser.getName();
+ if (NODE_IMI.equals(nodeName)) {
+ currentImiId = parser.getAttributeValue(null, ATTR_ID);
+ if (TextUtils.isEmpty(currentImiId)) {
+ Slog.w(TAG, "Invalid imi id found in subtypes.xml");
+ continue;
+ }
+ tempSubtypesArray = new ArrayList<>();
+ allSubtypes.put(currentImiId, tempSubtypesArray);
+ } else if (NODE_SUBTYPE.equals(nodeName)) {
+ if (TextUtils.isEmpty(currentImiId) || tempSubtypesArray == null) {
+ Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
+ continue;
+ }
+ final int icon = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_ICON));
+ final int label = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_LABEL));
+ final String imeSubtypeLocale =
+ parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
+ final String languageTag =
+ parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG);
+ final String imeSubtypeMode =
+ parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
+ final String imeSubtypeExtraValue =
+ parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
+ final boolean isAuxiliary = "1".equals(String.valueOf(
+ parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
+ final boolean isAsciiCapable = "1".equals(String.valueOf(
+ parser.getAttributeValue(null, ATTR_IS_ASCII_CAPABLE)));
+ final InputMethodSubtype.InputMethodSubtypeBuilder
+ builder = new InputMethodSubtype.InputMethodSubtypeBuilder()
+ .setSubtypeNameResId(label)
+ .setSubtypeIconResId(icon)
+ .setSubtypeLocale(imeSubtypeLocale)
+ .setLanguageTag(languageTag)
+ .setSubtypeMode(imeSubtypeMode)
+ .setSubtypeExtraValue(imeSubtypeExtraValue)
+ .setIsAuxiliary(isAuxiliary)
+ .setIsAsciiCapable(isAsciiCapable);
+ final String subtypeIdString =
+ parser.getAttributeValue(null, ATTR_IME_SUBTYPE_ID);
+ if (subtypeIdString != null) {
+ builder.setSubtypeId(Integer.parseInt(subtypeIdString));
+ }
+ tempSubtypesArray.add(builder.build());
+ }
+ }
+ } catch (XmlPullParserException | IOException | NumberFormatException e) {
+ Slog.w(TAG, "Error reading subtypes", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ad0886145496..5a7739c49b42 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -72,8 +72,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
-import android.os.Environment;
-import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
@@ -97,14 +95,12 @@ import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.EventLog;
import android.util.LruCache;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
-import android.util.Xml;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayInfo;
@@ -125,7 +121,6 @@ import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
@@ -147,7 +142,6 @@ import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -164,18 +158,10 @@ import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.wm.WindowManagerInternal;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
-import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -315,7 +301,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final WindowManagerInternal mWindowManagerInternal;
final HandlerCaller mCaller;
final boolean mHasFeature;
- private InputMethodFileManager mFileManager;
+ private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
+ new ArrayMap<>();
private final HardKeyboardListener mHardKeyboardListener;
private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager;
@@ -403,12 +390,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
};
private void restoreNonVrImeFromSettingsNoCheck() {
- mIsVrImeStarted = false;
// switch back to non-VR InputMethod from settings.
synchronized (mMethodMap) {
- final String lastInputId = mSettings.getSelectedInputMethod();
- setInputMethodLocked(lastInputId,
- mSettings.getSelectedInputMethodSubtypeId(lastInputId));
+ if (!mIsVrImeStarted) return;
+ mIsVrImeStarted = false;
+ updateFromSettingsLocked(false);
}
}
@@ -1221,7 +1207,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
int change = isPackageDisappearing(imi.getPackageName());
if (isPackageModified(imi.getPackageName())) {
- mFileManager.deleteAllInputMethodSubtypes(imiId);
+ mAdditionalSubtypeMap.remove(imi.getId());
+ AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
+ mSettings.getCurrentUserId());
}
if (change == PACKAGE_TEMPORARY_CHANGE
|| change == PACKAGE_PERMANENT_CHANGE) {
@@ -1453,7 +1441,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady);
updateCurrentProfileIds();
- mFileManager = new InputMethodFileManager(mMethodMap, userId);
+ AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mSettings, context);
// Register VR-state listener.
@@ -1499,8 +1487,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
!mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId);
mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
updateCurrentProfileIds();
- // InputMethodFileManager should be reset when the user is changed
- mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
+ // Additional subtypes should be reset when the user is changed
+ AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, newUserId);
final String defaultImiId = mSettings.getSelectedInputMethod();
if (DEBUG) Slog.d(TAG, "Switching user stage 2/3. newUserId=" + newUserId
@@ -3252,6 +3240,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// By this IPC call, only a process which shares the same uid with the IME can add
// additional input method subtypes to the IME.
if (TextUtils.isEmpty(imiId) || subtypes == null) return;
+ final ArrayList<InputMethodSubtype> toBeAdded = new ArrayList<>();
+ for (InputMethodSubtype subtype : subtypes) {
+ if (!toBeAdded.contains(subtype)) {
+ toBeAdded.add(subtype);
+ } else {
+ Slog.w(TAG, "Duplicated subtype definition found: "
+ + subtype.getLocale() + ", " + subtype.getMode());
+ }
+ }
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
return;
@@ -3273,10 +3270,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
for (int i = 0; i < packageNum; ++i) {
if (packageInfos[i].equals(imi.getPackageName())) {
if (subtypes.length > 0) {
- mFileManager.addInputMethodSubtypes(imi, subtypes);
+ mAdditionalSubtypeMap.put(imi.getId(), toBeAdded);
} else {
- mFileManager.deleteAllInputMethodSubtypes(imi.getId());
+ mAdditionalSubtypeMap.remove(imi.getId());
}
+ AdditionalSubtypeUtils.save(mAdditionalSubtypeMap, mMethodMap,
+ mSettings.getCurrentUserId());
final long ident = Binder.clearCallingIdentity();
try {
buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
@@ -3680,7 +3679,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mMyPackageMonitor.clearKnownImePackageNamesLocked();
queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
- mFileManager.getAllAdditionalInputMethodSubtypes(), mMethodMap, mMethodList);
+ mAdditionalSubtypeMap, mMethodMap, mMethodList);
// Construct the set of possible IME packages for onPackageChanged() to avoid false
// negatives when the package state remains to be the same but only the component state is
@@ -4162,231 +4161,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- // TODO: Cache the state for each user and reset when the cached user is removed.
- private static class InputMethodFileManager {
- private static final String SYSTEM_PATH = "system";
- private static final String INPUT_METHOD_PATH = "inputmethod";
- private static final String ADDITIONAL_SUBTYPES_FILE_NAME = "subtypes.xml";
- private static final String NODE_SUBTYPES = "subtypes";
- private static final String NODE_SUBTYPE = "subtype";
- private static final String NODE_IMI = "imi";
- private static final String ATTR_ID = "id";
- private static final String ATTR_LABEL = "label";
- private static final String ATTR_ICON = "icon";
- private static final String ATTR_IME_SUBTYPE_ID = "subtypeId";
- private static final String ATTR_IME_SUBTYPE_LOCALE = "imeSubtypeLocale";
- private static final String ATTR_IME_SUBTYPE_LANGUAGE_TAG = "languageTag";
- private static final String ATTR_IME_SUBTYPE_MODE = "imeSubtypeMode";
- private static final String ATTR_IME_SUBTYPE_EXTRA_VALUE = "imeSubtypeExtraValue";
- private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
- private static final String ATTR_IS_ASCII_CAPABLE = "isAsciiCapable";
- private final AtomicFile mAdditionalInputMethodSubtypeFile;
- private final ArrayMap<String, InputMethodInfo> mMethodMap;
- private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
- new ArrayMap<>();
- InputMethodFileManager(ArrayMap<String, InputMethodInfo> methodMap, int userId) {
- if (methodMap == null) {
- throw new NullPointerException("methodMap is null");
- }
- mMethodMap = methodMap;
- final File systemDir = userId == UserHandle.USER_SYSTEM
- ? new File(Environment.getDataDirectory(), SYSTEM_PATH)
- : Environment.getUserSystemDirectory(userId);
- final File inputMethodDir = new File(systemDir, INPUT_METHOD_PATH);
- final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
- mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile, "input-subtypes");
- readAdditionalInputMethodSubtypes(mAdditionalSubtypesMap,
- mAdditionalInputMethodSubtypeFile);
- }
-
- private void deleteAllInputMethodSubtypes(String imiId) {
- synchronized (mMethodMap) {
- mAdditionalSubtypesMap.remove(imiId);
- writeAdditionalInputMethodSubtypes(
- mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
- }
- }
-
- public void addInputMethodSubtypes(
- InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
- synchronized (mMethodMap) {
- final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
- final int N = additionalSubtypes.length;
- for (int i = 0; i < N; ++i) {
- final InputMethodSubtype subtype = additionalSubtypes[i];
- if (!subtypes.contains(subtype)) {
- subtypes.add(subtype);
- } else {
- Slog.w(TAG, "Duplicated subtype definition found: "
- + subtype.getLocale() + ", " + subtype.getMode());
- }
- }
- mAdditionalSubtypesMap.put(imi.getId(), subtypes);
- writeAdditionalInputMethodSubtypes(
- mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, mMethodMap);
- }
- }
-
- public ArrayMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
- synchronized (mMethodMap) {
- return mAdditionalSubtypesMap;
- }
- }
-
- private static void writeAdditionalInputMethodSubtypes(
- ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
- ArrayMap<String, InputMethodInfo> methodMap) {
- if (allSubtypes.isEmpty()) {
- if (subtypesFile.exists()) {
- subtypesFile.delete();
- }
- final File parentDir = subtypesFile.getBaseFile().getParentFile();
- if (parentDir != null && FileUtils.listFilesOrEmpty(parentDir).length == 0) {
- if (!parentDir.delete()) {
- Slog.e(TAG, "Failed to delete the empty parent directory " + parentDir);
- }
- }
- return;
- }
-
- final File parentDir = subtypesFile.getBaseFile().getParentFile();
- if (!parentDir.exists() && !parentDir.mkdirs()) {
- Slog.e(TAG, "Failed to create a parent directory " + parentDir);
- return;
- }
-
- // Safety net for the case that this function is called before methodMap is set.
- final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
- FileOutputStream fos = null;
- try {
- fos = subtypesFile.startWrite();
- final XmlSerializer out = new FastXmlSerializer();
- out.setOutput(fos, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- out.startTag(null, NODE_SUBTYPES);
- for (String imiId : allSubtypes.keySet()) {
- if (isSetMethodMap && !methodMap.containsKey(imiId)) {
- Slog.w(TAG, "IME uninstalled or not valid.: " + imiId);
- continue;
- }
- out.startTag(null, NODE_IMI);
- out.attribute(null, ATTR_ID, imiId);
- final List<InputMethodSubtype> subtypesList = allSubtypes.get(imiId);
- final int N = subtypesList.size();
- for (int i = 0; i < N; ++i) {
- final InputMethodSubtype subtype = subtypesList.get(i);
- out.startTag(null, NODE_SUBTYPE);
- if (subtype.hasSubtypeId()) {
- out.attribute(null, ATTR_IME_SUBTYPE_ID,
- String.valueOf(subtype.getSubtypeId()));
- }
- out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
- out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
- out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
- out.attribute(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG,
- subtype.getLanguageTag());
- out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
- out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
- out.attribute(null, ATTR_IS_AUXILIARY,
- String.valueOf(subtype.isAuxiliary() ? 1 : 0));
- out.attribute(null, ATTR_IS_ASCII_CAPABLE,
- String.valueOf(subtype.isAsciiCapable() ? 1 : 0));
- out.endTag(null, NODE_SUBTYPE);
- }
- out.endTag(null, NODE_IMI);
- }
- out.endTag(null, NODE_SUBTYPES);
- out.endDocument();
- subtypesFile.finishWrite(fos);
- } catch (java.io.IOException e) {
- Slog.w(TAG, "Error writing subtypes", e);
- if (fos != null) {
- subtypesFile.failWrite(fos);
- }
- }
- }
-
- private static void readAdditionalInputMethodSubtypes(
- ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
- if (allSubtypes == null || subtypesFile == null) return;
- allSubtypes.clear();
- if (!subtypesFile.exists()) {
- // Not having the file means there is no additional subtype.
- return;
- }
- try (final FileInputStream fis = subtypesFile.openRead()) {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, StandardCharsets.UTF_8.name());
- int type = parser.getEventType();
- // Skip parsing until START_TAG
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {}
- String firstNodeName = parser.getName();
- if (!NODE_SUBTYPES.equals(firstNodeName)) {
- throw new XmlPullParserException("Xml doesn't start with subtypes");
- }
- final int depth =parser.getDepth();
- String currentImiId = null;
- ArrayList<InputMethodSubtype> tempSubtypesArray = null;
- while (((type = parser.next()) != XmlPullParser.END_TAG
- || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if (type != XmlPullParser.START_TAG)
- continue;
- final String nodeName = parser.getName();
- if (NODE_IMI.equals(nodeName)) {
- currentImiId = parser.getAttributeValue(null, ATTR_ID);
- if (TextUtils.isEmpty(currentImiId)) {
- Slog.w(TAG, "Invalid imi id found in subtypes.xml");
- continue;
- }
- tempSubtypesArray = new ArrayList<>();
- allSubtypes.put(currentImiId, tempSubtypesArray);
- } else if (NODE_SUBTYPE.equals(nodeName)) {
- if (TextUtils.isEmpty(currentImiId) || tempSubtypesArray == null) {
- Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
- continue;
- }
- final int icon = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_ICON));
- final int label = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_LABEL));
- final String imeSubtypeLocale =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
- final String languageTag =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG);
- final String imeSubtypeMode =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
- final String imeSubtypeExtraValue =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
- final boolean isAuxiliary = "1".equals(String.valueOf(
- parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
- final boolean isAsciiCapable = "1".equals(String.valueOf(
- parser.getAttributeValue(null, ATTR_IS_ASCII_CAPABLE)));
- final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder()
- .setSubtypeNameResId(label)
- .setSubtypeIconResId(icon)
- .setSubtypeLocale(imeSubtypeLocale)
- .setLanguageTag(languageTag)
- .setSubtypeMode(imeSubtypeMode)
- .setSubtypeExtraValue(imeSubtypeExtraValue)
- .setIsAuxiliary(isAuxiliary)
- .setIsAsciiCapable(isAsciiCapable);
- final String subtypeIdString =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_ID);
- if (subtypeIdString != null) {
- builder.setSubtypeId(Integer.parseInt(subtypeIdString));
- }
- tempSubtypesArray.add(builder.build());
- }
- }
- } catch (XmlPullParserException | IOException | NumberFormatException e) {
- Slog.w(TAG, "Error reading subtypes", e);
- return;
- }
- }
- }
-
private static final class LocalServiceImpl extends InputMethodManagerInternal {
@NonNull
private final InputMethodManagerService mService;
@@ -4620,17 +4394,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@RequiresPermission(allOf = {
+ Manifest.permission.DUMP,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Manifest.permission.WRITE_SECURE_SETTINGS,
- Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+ })
@BinderThread
@ShellCommandResult
@Override
public int onCommand(@Nullable String cmd) {
// For shell command, require all the permissions here in favor of code simplicity.
- mService.mContext.enforceCallingPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
- mService.mContext.enforceCallingPermission(
- Manifest.permission.WRITE_SECURE_SETTINGS, null);
+ Arrays.asList(
+ Manifest.permission.DUMP,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.WRITE_SECURE_SETTINGS
+ ).forEach(permission -> mService.mContext.enforceCallingPermission(permission, null));
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index b6954fc9a8f1..05d77ab5867e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -188,7 +188,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int ADD_LISTENER = 8;
private static final int REMOVE_LISTENER = 9;
private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
- private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
+ private static final int SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED = 12;
private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_SUPL_CONNECTION = 14;
private static final int RELEASE_SUPL_CONNECTION = 15;
@@ -411,9 +411,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
- // SIM/Carrier info.
- private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
-
// Persist property for LPP_PROFILE
private final static String LPP_PROFILE = "persist.sys.gps.lpp";
@@ -483,18 +480,20 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case Intent.ACTION_SCREEN_ON:
updateLowPowerMode();
break;
- case SIM_STATE_CHANGED:
- subscriptionOrSimChanged(context);
+ case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
+ subscriptionOrCarrierConfigChanged(context);
break;
}
}
};
+ // TODO(b/119326010): replace OnSubscriptionsChangedListener with
+ // ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED broadcast reseiver.
private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
- sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
+ sendMessage(SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED, 0, null);
}
};
@@ -506,7 +505,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
}
- private void subscriptionOrSimChanged(Context context) {
+ private void subscriptionOrCarrierConfigChanged(Context context) {
if (DEBUG) Log.d(TAG, "received SIM related action: ");
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -521,12 +520,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
PersistableBundle b = configManager.getConfig();
if (b != null) {
isKeepLppProfile =
- b.getBoolean(CarrierConfigManager.KEY_PERSIST_LPP_MODE_BOOL);
+ b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL);
}
}
if (isKeepLppProfile) {
// load current properties for the carrier
- loadPropertiesFromResource(context, mProperties);
+ loadPropertiesFromCarrierConfig(context, mProperties);
String lpp_profile = mProperties.getProperty("LPP_PROFILE");
// set the persist property LPP_PROFILE for the value
if (lpp_profile != null) {
@@ -571,7 +570,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private void reloadGpsProperties(Context context, Properties properties) {
if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
- loadPropertiesFromResource(context, properties);
+ loadPropertiesFromCarrierConfig(context, properties);
String lpp_prof = SystemProperties.get(LPP_PROFILE);
if (!TextUtils.isEmpty(lpp_prof)) {
@@ -581,7 +580,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
/*
* Overlay carrier properties from a debug configuration file.
*/
- loadPropertiesFromFile(properties);
+ loadPropertiesFromGpsDebugConfig(properties);
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
properties.getProperty("SUPL_PORT"));
@@ -651,25 +650,34 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- private void loadPropertiesFromResource(Context context,
- Properties properties) {
- String[] configValues = context.getResources().getStringArray(
- com.android.internal.R.array.config_gpsParameters);
- for (String item : configValues) {
- if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
- // We need to support "KEY =", but not "=VALUE".
- int index = item.indexOf("=");
- if (index > 0 && index + 1 < item.length()) {
- String key = item.substring(0, index);
- String value = item.substring(index + 1);
- properties.setProperty(key.trim().toUpperCase(), value);
- } else {
- Log.w(TAG, "malformed contents: " + item);
+ private void loadPropertiesFromCarrierConfig(Context context, Properties properties) {
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager == null) {
+ return;
+ }
+ PersistableBundle configs = configManager.getConfigForSubId(
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ if (configs == null) {
+ if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
+ configs = CarrierConfigManager.getDefaultConfig();
+ }
+ for (String configKey : configs.keySet()) {
+ if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
+ String key = configKey
+ .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
+ .toUpperCase();
+ Object value = configs.get(configKey);
+ if (value instanceof String) {
+ // All GPS properties are of String type; convert so.
+ if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
+ properties.setProperty(key, (String) value);
+ }
}
}
}
- private void loadPropertiesFromFile(Properties properties) {
+ private void loadPropertiesFromGpsDebugConfig(Properties properties) {
try {
File file = new File(DEBUG_PROPERTIES_FILE);
FileInputStream stream = null;
@@ -2017,8 +2025,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case UPDATE_LOCATION:
handleUpdateLocation((Location) msg.obj);
break;
- case SUBSCRIPTION_OR_SIM_CHANGED:
- subscriptionOrSimChanged(mContext);
+ case SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED:
+ subscriptionOrCarrierConfigChanged(mContext);
break;
case INITIALIZE_HANDLER:
handleInitialize();
@@ -2085,7 +2093,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
- intentFilter.addAction(SIM_STATE_CHANGED);
+ intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
mNetworkConnectivityHandler.registerNetworkCallbacks();
@@ -2167,8 +2175,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return "DOWNLOAD_XTRA_DATA_FINISHED";
case UPDATE_LOCATION:
return "UPDATE_LOCATION";
- case SUBSCRIPTION_OR_SIM_CHANGED:
- return "SUBSCRIPTION_OR_SIM_CHANGED";
+ case SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED:
+ return "SUBSCRIPTION_OR_CARRIER_CONFIG_CHANGED";
case INITIALIZE_HANDLER:
return "INITIALIZE_HANDLER";
case REPORT_LOCATION:
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index c1f3468627cb..139d8ac6a8d5 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -236,6 +236,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
* {@link AudioManager#ADJUST_SAME}.
*
* @param packageName The package that made the original volume request.
+ * @param opPackageName The op package that made the original volume request.
* @param pid The pid that made the original volume request.
* @param uid The uid that made the original volume request.
* @param caller caller binder. can be {@code null} if it's from the volume key.
@@ -248,7 +249,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
* @param flags Any of the flags from {@link AudioManager}.
* @param useSuggested True to use adjustSuggestedStreamVolume instead of
*/
- public void adjustVolume(String packageName, int pid, int uid,
+ public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
ISessionControllerCallback caller, boolean asSystemService, int direction, int flags,
boolean useSuggested) {
int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
@@ -258,8 +259,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
// Adjust the volume with a handler not to be blocked by other system service.
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
- postAdjustLocalVolume(stream, direction, flags, packageName, uid, asSystemService,
- useSuggested, previousFlagPlaySound);
+ postAdjustLocalVolume(stream, direction, flags, opPackageName, pid, uid,
+ asSystemService, useSuggested, previousFlagPlaySound);
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
// Nothing to do, the volume cannot be changed
@@ -290,11 +291,23 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
- private void setVolumeTo(String packageName, int pid, int uid,
+ private void setVolumeTo(String packageName, String opPackageName, int pid, int uid,
ISessionControllerCallback caller, int value, int flags) {
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
- mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
+ final int volumeValue = value;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mAudioManagerInternal.setStreamVolumeForUid(stream, volumeValue, flags,
+ opPackageName, uid);
+ } catch (IllegalArgumentException | SecurityException e) {
+ Log.e(TAG, "Cannot set volume: stream=" + stream + ", value=" + volumeValue
+ + ", flags=" + flags, e);
+ }
+ }
+ });
} else {
if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
// Nothing to do. The volume can't be set directly.
@@ -465,11 +478,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
- final String callingPackageName, final int callingUid, final boolean asSystemService,
- final boolean useSuggested, final int previousFlagPlaySound) {
- final String packageName = asSystemService
- ? mContext.getOpPackageName() : callingPackageName;
- final int uid = asSystemService ? Process.SYSTEM_UID : callingUid;
+ final String callingOpPackageName, final int callingPid, final int callingUid,
+ final boolean asSystemService, final boolean useSuggested,
+ final int previousFlagPlaySound) {
+ // Must use opPackageName for adjusting volumes with UID.
+ final String opPackageName;
+ final int uid;
+ if (asSystemService) {
+ opPackageName = mContext.getOpPackageName();
+ uid = Process.SYSTEM_UID;
+ } else {
+ opPackageName = callingOpPackageName;
+ uid = callingUid;
+ }
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -477,19 +498,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
if (useSuggested) {
if (AudioSystem.isStreamActive(stream, 0)) {
mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream,
- direction, flags, packageName, uid);
+ direction, flags, opPackageName, uid);
} else {
mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
- flags | previousFlagPlaySound, packageName, uid);
+ flags | previousFlagPlaySound, opPackageName, uid);
}
} else {
mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
- packageName, uid);
+ opPackageName, uid);
}
} catch (IllegalArgumentException | SecurityException e) {
Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream="
- + stream + ", flags=" + flags + ", packageName=" + packageName
+ + stream + ", flags=" + flags + ", opPackageName=" + opPackageName
+ ", uid=" + uid + ", useSuggested=" + useSuggested
+ ", previousFlagPlaySound=" + previousFlagPlaySound, e);
}
@@ -1232,27 +1253,29 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
- public void adjustVolume(String packageName, ISessionControllerCallback caller,
- boolean asSystemService, int direction, int flags) {
+ public void adjustVolume(String packageName, String opPackageName,
+ ISessionControllerCallback caller, boolean asSystemService, int direction,
+ int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- MediaSessionRecord.this.adjustVolume(packageName, pid, uid, caller, asSystemService,
- direction, flags, false /* useSuggested */);
+ MediaSessionRecord.this.adjustVolume(packageName, opPackageName, pid, uid, caller,
+ asSystemService, direction, flags, false /* useSuggested */);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void setVolumeTo(String packageName, ISessionControllerCallback caller,
- int value, int flags) {
+ public void setVolumeTo(String packageName, String opPackageName,
+ ISessionControllerCallback caller, int value, int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, caller, value, flags);
+ MediaSessionRecord.this.setVolumeTo(packageName, opPackageName, pid, uid, caller,
+ value, flags);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 40ae2d95482e..052d5797c1e7 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -35,10 +35,12 @@ import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioManager;
+import android.media.AudioManagerInternal;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
+import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
@@ -72,6 +74,7 @@ import android.view.KeyEvent;
import android.view.ViewConfiguration;
import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
@@ -108,6 +111,8 @@ public class MediaSessionService extends SystemService implements Monitor {
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
+ private AudioManagerInternal mAudioManagerInternal;
+ private ActivityManager mActivityManager;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
private boolean mHasFeatureLeanback;
@@ -139,6 +144,9 @@ public class MediaSessionService extends SystemService implements Monitor {
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
+ mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+ mActivityManager =
+ (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
mAudioPlayerStateMonitor.registerListener(
(config, isRemoved) -> {
@@ -888,6 +896,21 @@ public class MediaSessionService extends SystemService implements Monitor {
}
@Override
+ public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "Session2 is created " + sessionToken);
+ }
+ // TODO: Keep the session.
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public List<IBinder> getSessions(ComponentName componentName, int userId) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -1202,7 +1225,8 @@ public class MediaSessionService extends SystemService implements Monitor {
* there's no active global priority session, long-pressess will be sent to the
* long-press listener instead of adjusting volume.
*
- * @param packageName The caller package.
+ * @param packageName The caller's package name, obtained by Context#getPackageName()
+ * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
* @param asSystemService {@code true} if the event sent to the session as if it was come
* from the system service instead of the app process. This helps sessions to
* distinguish between the key injection by the app and key events from the
@@ -1217,8 +1241,8 @@ public class MediaSessionService extends SystemService implements Monitor {
* @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
*/
@Override
- public void dispatchVolumeKeyEvent(String packageName, boolean asSystemService,
- KeyEvent keyEvent, int stream, boolean musicOnly) {
+ public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
+ boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
if (keyEvent == null ||
(keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
&& keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
@@ -1240,8 +1264,8 @@ public class MediaSessionService extends SystemService implements Monitor {
synchronized (mLock) {
if (isGlobalPriorityActiveLocked()
|| mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
- dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
- keyEvent, stream, musicOnly);
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
} else {
// TODO: Consider the case when both volume up and down keys are pressed
// at the same time.
@@ -1274,12 +1298,13 @@ public class MediaSessionService extends SystemService implements Monitor {
&& mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
.getDownTime() == keyEvent.getDownTime()) {
// Short-press. Should change volume.
- dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService,
mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
mCurrentFullUserRecord.mInitialDownVolumeStream,
mCurrentFullUserRecord.mInitialDownMusicOnly);
- dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
- keyEvent, stream, musicOnly);
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
} else {
dispatchVolumeKeyLongPressLocked(keyEvent);
}
@@ -1291,8 +1316,9 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- private void dispatchVolumeKeyEventLocked(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
+ private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
+ int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
+ boolean musicOnly) {
boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
int direction = 0;
@@ -1326,26 +1352,26 @@ public class MediaSessionService extends SystemService implements Monitor {
if (up) {
direction = 0;
}
- dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
- direction, flags);
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+ asSystemService, stream, direction, flags);
} else if (isMute) {
if (down && keyEvent.getRepeatCount() == 0) {
- dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
- AudioManager.ADJUST_TOGGLE_MUTE, flags);
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+ asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
}
}
}
}
@Override
- public void dispatchAdjustVolume(String packageName, int suggestedStream, int delta,
- int flags) {
+ public void dispatchAdjustVolume(String packageName, String opPackageName,
+ int suggestedStream, int delta, int flags) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- dispatchAdjustVolumeLocked(packageName, pid, uid, false,
+ dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
suggestedStream, delta, flags);
}
} finally {
@@ -1409,24 +1435,14 @@ public class MediaSessionService extends SystemService implements Monitor {
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- int controllerUserId = UserHandle.getUserId(controllerUid);
- int controllerUidFromPackageName;
- try {
- controllerUidFromPackageName = getContext().getPackageManager()
- .getPackageUidAsUser(controllerPackageName, controllerUserId);
- } catch (NameNotFoundException e) {
- if (DEBUG) {
- Log.d(TAG, "Package " + controllerPackageName + " doesn't exist");
- }
- return false;
- }
- if (controllerUidFromPackageName != controllerUid) {
- if (DEBUG) {
- Log.d(TAG, "Package name " + controllerPackageName
- + " doesn't match with the uid " + controllerUid);
- }
- return false;
- }
+ // Don't perform sanity check between controllerPackageName and controllerUid.
+ // When an (activity|service) runs on the another apps process by specifying
+ // android:process in the AndroidManifest.xml, then PID and UID would have the
+ // running process' information instead of the (activity|service) that has created
+ // MediaController.
+ // Note that we can use Context#getOpPackageName() instead of
+ // Context#getPackageName() for getting package name that matches with the PID/UID,
+ // but it doesn't tell which package has created the MediaController, so useless.
return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
controllerPid, controllerUid);
} finally {
@@ -1497,8 +1513,8 @@ public class MediaSessionService extends SystemService implements Monitor {
return false;
}
- private void dispatchAdjustVolumeLocked(String packageName, int pid, int uid,
- boolean asSystemService, int suggestedStream, int direction, int flags) {
+ private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
+ int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
: mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
@@ -1529,21 +1545,28 @@ public class MediaSessionService extends SystemService implements Monitor {
mHandler.post(new Runnable() {
@Override
public void run() {
+ final String callingOpPackageName;
+ final int callingUid;
+ if (asSystemService) {
+ callingOpPackageName = getContext().getOpPackageName();
+ callingUid = Process.myUid();
+ } else {
+ callingOpPackageName = opPackageName;
+ callingUid = uid;
+ }
try {
- String packageName = getContext().getOpPackageName();
- mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
- flags, packageName, TAG);
- } catch (RemoteException|SecurityException e) {
- Log.e(TAG, "Error adjusting default volume.", e);
- } catch (IllegalArgumentException e) {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
+ direction, flags, callingOpPackageName, callingUid);
+ } catch (SecurityException | IllegalArgumentException e) {
Log.e(TAG, "Cannot adjust volume: direction=" + direction
- + ", suggestedStream=" + suggestedStream + ", flags=" + flags,
- e);
+ + ", suggestedStream=" + suggestedStream + ", flags=" + flags
+ + ", packageName=" + packageName + ", uid=" + uid
+ + ", asSystemService=" + asSystemService, e);
}
}
});
} else {
- session.adjustVolume(packageName, pid, uid, null, asSystemService,
+ session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
direction, flags, true);
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 6187583a0253..88d73fb10902 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -558,7 +558,7 @@ abstract public class ManagedServices {
if (pkgList != null && (pkgList.length > 0)) {
boolean anyServicesInvolved = false;
// Remove notification settings for uninstalled package
- if (removingPackage) {
+ if (removingPackage && uidList != null) {
int size = Math.min(pkgList.length, uidList.length);
for (int i = 0; i < size; i++) {
final String pkg = pkgList[i];
@@ -570,9 +570,11 @@ abstract public class ManagedServices {
if (mEnabledServicesPackageNames.contains(pkgName)) {
anyServicesInvolved = true;
}
- for (int uid : uidList) {
- if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
- anyServicesInvolved = true;
+ if (uidList != null && uidList.length > 0) {
+ for (int uid : uidList) {
+ if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
+ anyServicesInvolved = true;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d961bad1cf59..c2c88258b067 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -75,6 +75,8 @@ import static android.service.notification.NotificationListenerService.TRIM_FULL
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -144,7 +146,6 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
-import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -1315,6 +1316,11 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void setHints(int hints) {
+ mListenerHints = hints;
+ }
+
+ @VisibleForTesting
void setVibrator(Vibrator vibrator) {
mVibrator = vibrator;
}
@@ -3852,7 +3858,8 @@ public class NotificationManagerService extends SystemService {
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
- new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
+ new NotificationShellCmd(NotificationManagerService.this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
}
};
@@ -3990,6 +3997,20 @@ public class NotificationManagerService extends SystemService {
if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
return "listenerHints";
}
+ if (record != null && record.getAudioAttributes() != null) {
+ if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
+ if (record.getAudioAttributes().getUsage()
+ != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+ return "listenerNoti";
+ }
+ }
+ if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
+ if (record.getAudioAttributes().getUsage()
+ == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+ return "listenerCall";
+ }
+ }
+ }
if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
return "callState";
}
@@ -4420,6 +4441,8 @@ public class NotificationManagerService extends SystemService {
if (pendingIntent != null) {
am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
WHITELIST_TOKEN, duration);
+ am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
+ WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER));
}
}
}
@@ -5258,22 +5281,25 @@ public class NotificationManagerService extends SystemService {
}
if (DBG) Slog.v(TAG, "Interrupting!");
if (hasValidSound) {
- mSoundNotificationKey = key;
if (mInCall) {
playInCallNotification();
beep = true;
} else {
beep = playSound(record, soundUri);
}
+ if(beep) {
+ mSoundNotificationKey = key;
+ }
}
final boolean ringerModeSilent =
mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT;
if (!mInCall && hasValidVibrate && !ringerModeSilent) {
- mVibrateNotificationKey = key;
-
buzz = playVibration(record, vibration, hasValidSound);
+ if(buzz) {
+ mVibrateNotificationKey = key;
+ }
}
} else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
hasValidSound = false;
@@ -5454,8 +5480,17 @@ public class NotificationManagerService extends SystemService {
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) { }
- mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
- effect, "Notification (delayed)", record.getAudioAttributes());
+
+ // Notifications might be canceled before it actually vibrates due to waitMs,
+ // so need to check the notification still valide for vibrate.
+ synchronized (mNotificationLock) {
+ if (mNotificationsByKey.get(record.getKey()) != null) {
+ mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+ effect, "Notification (delayed)", record.getAudioAttributes());
+ } else {
+ Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
+ }
+ }
}).start();
} else {
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
@@ -7715,110 +7750,6 @@ public class NotificationManagerService extends SystemService {
}
}
- private class ShellCmd extends ShellCommand {
- public static final String USAGE = "help\n"
- + "allow_listener COMPONENT [user_id]\n"
- + "disallow_listener COMPONENT [user_id]\n"
- + "allow_assistant COMPONENT\n"
- + "remove_assistant COMPONENT\n"
- + "allow_dnd PACKAGE\n"
- + "disallow_dnd PACKAGE\n"
- + "suspend_package PACKAGE\n"
- + "unsuspend_package PACKAGE";
-
- @Override
- public int onCommand(String cmd) {
- if (cmd == null) {
- return handleDefaultCommands(cmd);
- }
- final PrintWriter pw = getOutPrintWriter();
- try {
- switch (cmd) {
- case "allow_dnd": {
- getBinderService().setNotificationPolicyAccessGranted(
- getNextArgRequired(), true);
- }
- break;
-
- case "disallow_dnd": {
- getBinderService().setNotificationPolicyAccessGranted(
- getNextArgRequired(), false);
- }
- break;
- case "allow_listener": {
- ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
- if (cn == null) {
- pw.println("Invalid listener - must be a ComponentName");
- return -1;
- }
- String userId = getNextArg();
- if (userId == null) {
- getBinderService().setNotificationListenerAccessGranted(cn, true);
- } else {
- getBinderService().setNotificationListenerAccessGrantedForUser(
- cn, Integer.parseInt(userId), true);
- }
- }
- break;
- case "disallow_listener": {
- ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
- if (cn == null) {
- pw.println("Invalid listener - must be a ComponentName");
- return -1;
- }
- String userId = getNextArg();
- if (userId == null) {
- getBinderService().setNotificationListenerAccessGranted(cn, false);
- } else {
- getBinderService().setNotificationListenerAccessGrantedForUser(
- cn, Integer.parseInt(userId), false);
- }
- }
- break;
- case "allow_assistant": {
- ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
- if (cn == null) {
- pw.println("Invalid assistant - must be a ComponentName");
- return -1;
- }
- getBinderService().setNotificationAssistantAccessGranted(cn, true);
- }
- break;
- case "disallow_assistant": {
- ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
- if (cn == null) {
- pw.println("Invalid assistant - must be a ComponentName");
- return -1;
- }
- getBinderService().setNotificationAssistantAccessGranted(cn, false);
- }
- break;
- case "suspend_package": {
- // only use for testing
- simulatePackageSuspendBroadcast(true, getNextArgRequired());
- }
- break;
- case "unsuspend_package": {
- // only use for testing
- simulatePackageSuspendBroadcast(false, getNextArgRequired());
- }
- break;
- default:
- return handleDefaultCommands(cmd);
- }
- } catch (Exception e) {
- pw.println("Error occurred. Check logcat for details. " + e.getMessage());
- Slog.e(TAG, "Error running shell command", e);
- }
- return 0;
- }
-
- @Override
- public void onHelp() {
- getOutPrintWriter().println(USAGE);
- }
- }
-
private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
new file mode 100644
index 000000000000..3d88f20f0710
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.util.Collections;
+
+/**
+ * Implementation of `cmd notification` in NotificationManagerService.
+ */
+public class NotificationShellCmd extends ShellCommand {
+ private static final String USAGE =
+ "usage: cmd notification SUBCMD [args]\n\n"
+ + "SUBCMDs:\n"
+ + " allow_listener COMPONENT [user_id]\n"
+ + " disallow_listener COMPONENT [user_id]\n"
+ + " allow_assistant COMPONENT\n"
+ + " remove_assistant COMPONENT\n"
+ + " allow_dnd PACKAGE\n"
+ + " disallow_dnd PACKAGE\n"
+ + " suspend_package PACKAGE\n"
+ + " unsuspend_package PACKAGE\n"
+ + " post [--help | flags] TAG TEXT";
+
+ private static final String NOTIFY_USAGE =
+ "usage: cmd notification post [flags] <tag> <text>\n\n"
+ + "flags:\n"
+ + " -h|--help\n"
+ + " -v|--verbose\n"
+ + " -t|--title <text>\n"
+ + " -i|--icon <iconspec>\n"
+ + " -I|--large-icon <iconspec>\n"
+ + " -S|--style <style> [styleargs]\n"
+ + " -c|--content-intent <intentspec>\n"
+ + "\n"
+ + "styles: (default none)\n"
+ + " bigtext\n"
+ + " bigpicture --picture <iconspec>\n"
+ + " inbox --line <text> --line <text> ...\n"
+ + " messaging --conversation <title> --message <who>:<text> ...\n"
+ + " media\n"
+ + "\n"
+ + "an <iconspec> is one of\n"
+ + " file:///data/local/tmp/<img.png>\n"
+ + " content://<provider>/<path>\n"
+ + " @[<package>:]drawable/<img>\n"
+ + " data:base64,<B64DATA==>\n"
+ + "\n"
+ + "an <intentspec> is (broadcast|service|activity) <args>\n"
+ + " <args> are as described in `am start`";
+
+ public static final int NOTIFICATION_ID = 1138;
+ public static final String NOTIFICATION_PACKAGE = "com.android.shell";
+ public static final String CHANNEL_ID = "shellcmd";
+ public static final String CHANNEL_NAME = "Shell command";
+ public static final int CHANNEL_IMP = NotificationManager.IMPORTANCE_DEFAULT;
+
+ private final NotificationManagerService mDirectService;
+ private final INotificationManager mBinderService;
+
+ public NotificationShellCmd(NotificationManagerService service) {
+ mDirectService = service;
+ mBinderService = service.getBinderService();
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch (cmd.replace('-', '_')) {
+ case "allow_dnd": {
+ mBinderService.setNotificationPolicyAccessGranted(
+ getNextArgRequired(), true);
+ }
+ break;
+
+ case "disallow_dnd": {
+ mBinderService.setNotificationPolicyAccessGranted(
+ getNextArgRequired(), false);
+ }
+ break;
+ case "allow_listener": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid listener - must be a ComponentName");
+ return -1;
+ }
+ String userId = getNextArg();
+ if (userId == null) {
+ mBinderService.setNotificationListenerAccessGranted(cn, true);
+ } else {
+ mBinderService.setNotificationListenerAccessGrantedForUser(
+ cn, Integer.parseInt(userId), true);
+ }
+ }
+ break;
+ case "disallow_listener": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid listener - must be a ComponentName");
+ return -1;
+ }
+ String userId = getNextArg();
+ if (userId == null) {
+ mBinderService.setNotificationListenerAccessGranted(cn, false);
+ } else {
+ mBinderService.setNotificationListenerAccessGrantedForUser(
+ cn, Integer.parseInt(userId), false);
+ }
+ }
+ break;
+ case "allow_assistant": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid assistant - must be a ComponentName");
+ return -1;
+ }
+ mBinderService.setNotificationAssistantAccessGranted(cn, true);
+ }
+ break;
+ case "disallow_assistant": {
+ ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
+ if (cn == null) {
+ pw.println("Invalid assistant - must be a ComponentName");
+ return -1;
+ }
+ mBinderService.setNotificationAssistantAccessGranted(cn, false);
+ }
+ break;
+ case "suspend_package": {
+ // only use for testing
+ mDirectService.simulatePackageSuspendBroadcast(true, getNextArgRequired());
+ }
+ break;
+ case "unsuspend_package": {
+ // only use for testing
+ mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
+ }
+ break;
+ case "post":
+ case "notify":
+ doNotify(pw);
+ break;
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (Exception e) {
+ pw.println("Error occurred. Check logcat for details. " + e.getMessage());
+ Slog.e(NotificationManagerService.TAG, "Error running shell command", e);
+ }
+ return 0;
+ }
+
+ void ensureChannel() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+ final int userid = UserHandle.getCallingUserId();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (mBinderService.getNotificationChannelForPackage(NOTIFICATION_PACKAGE,
+ uid, CHANNEL_ID, false) == null) {
+ final NotificationChannel chan = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
+ CHANNEL_IMP);
+ Slog.v(NotificationManagerService.TAG,
+ "creating shell channel for user " + userid + " uid " + uid + ": " + chan);
+ mBinderService.createNotificationChannelsForPackage(NOTIFICATION_PACKAGE, uid,
+ new ParceledListSlice<NotificationChannel>(
+ Collections.singletonList(chan)));
+ Slog.v(NotificationManagerService.TAG, "created channel: "
+ + mBinderService.getNotificationChannelForPackage(NOTIFICATION_PACKAGE,
+ uid, CHANNEL_ID, false));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ Icon parseIcon(Resources res, String encoded) throws IllegalArgumentException {
+ if (TextUtils.isEmpty(encoded)) return null;
+ if (encoded.startsWith("/")) {
+ encoded = "file://" + encoded;
+ }
+ if (encoded.startsWith("http:")
+ || encoded.startsWith("https:")
+ || encoded.startsWith("content:")
+ || encoded.startsWith("file:")
+ || encoded.startsWith("android.resource:")) {
+ Uri asUri = Uri.parse(encoded);
+ return Icon.createWithContentUri(asUri);
+ } else if (encoded.startsWith("@")) {
+ final int resid = res.getIdentifier(encoded.substring(1),
+ "drawable", "android");
+ if (resid != 0) {
+ return Icon.createWithResource(res, resid);
+ }
+ } else if (encoded.startsWith("data:")) {
+ encoded = encoded.substring(encoded.indexOf(',') + 1);
+ byte[] bits = android.util.Base64.decode(encoded, android.util.Base64.DEFAULT);
+ return Icon.createWithData(bits, 0, bits.length);
+ }
+ return null;
+ }
+
+ private int doNotify(PrintWriter pw) throws RemoteException, URISyntaxException {
+ final Context context = mDirectService.getContext();
+ final Resources res = context.getResources();
+ final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID);
+ String opt;
+
+ boolean verbose = false;
+ Notification.BigPictureStyle bigPictureStyle = null;
+ Notification.BigTextStyle bigTextStyle = null;
+ Notification.InboxStyle inboxStyle = null;
+ Notification.MediaStyle mediaStyle = null;
+ Notification.MessagingStyle messagingStyle = null;
+
+ Icon smallIcon = null;
+ while ((opt = getNextOption()) != null) {
+ boolean large = false;
+ switch (opt) {
+ case "-v":
+ case "--verbose":
+ verbose = true;
+ break;
+ case "-t":
+ case "--title":
+ case "title":
+ builder.setContentTitle(getNextArgRequired());
+ break;
+ case "-I":
+ case "--large-icon":
+ case "--largeicon":
+ case "largeicon":
+ case "large-icon":
+ large = true;
+ // fall through
+ case "-i":
+ case "--icon":
+ case "icon":
+ final String iconSpec = getNextArgRequired();
+ final Icon icon = parseIcon(res, iconSpec);
+ if (icon == null) {
+ pw.println("error: invalid icon: " + iconSpec);
+ return -1;
+ }
+ if (large) {
+ builder.setLargeIcon(icon);
+ large = false;
+ } else {
+ smallIcon = icon;
+ }
+ break;
+ case "-c":
+ case "--content-intent":
+ case "content-intent":
+ case "--intent":
+ case "intent":
+ String intentKind = null;
+ switch (peekNextArg()) {
+ case "broadcast":
+ case "service":
+ case "activity":
+ intentKind = getNextArg();
+ }
+ final Intent intent = Intent.parseCommandArgs(this, null);
+ if (intent.getData() == null) {
+ // force unique intents unless you know what you're doing
+ intent.setData(Uri.parse("xyz:" + System.currentTimeMillis()));
+ }
+ final PendingIntent pi;
+ if ("broadcast".equals(intentKind)) {
+ pi = PendingIntent.getBroadcastAsUser(
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
+ UserHandle.CURRENT);
+ } else if ("service".equals(intentKind)) {
+ pi = PendingIntent.getService(
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ } else {
+ pi = PendingIntent.getActivityAsUser(
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, null,
+ UserHandle.CURRENT);
+ }
+ builder.setContentIntent(pi);
+ break;
+ case "-S":
+ case "--style":
+ final String styleSpec = getNextArgRequired().toLowerCase();
+ switch (styleSpec) {
+ case "bigtext":
+ bigTextStyle = new Notification.BigTextStyle();
+ builder.setStyle(bigTextStyle);
+ break;
+ case "bigpicture":
+ bigPictureStyle = new Notification.BigPictureStyle();
+ builder.setStyle(bigPictureStyle);
+ break;
+ case "inbox":
+ inboxStyle = new Notification.InboxStyle();
+ builder.setStyle(inboxStyle);
+ break;
+ case "messaging":
+ String name = "You";
+ if ("--user".equals(peekNextArg())) {
+ getNextArg();
+ name = getNextArgRequired();
+ }
+ messagingStyle = new Notification.MessagingStyle(
+ new Person.Builder().setName(name).build());
+ builder.setStyle(messagingStyle);
+ break;
+ case "media":
+ mediaStyle = new Notification.MediaStyle();
+ builder.setStyle(mediaStyle);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unrecognized notification style: " + styleSpec);
+ }
+ break;
+ case "--bigText": case "--bigtext": case "--big-text":
+ if (bigTextStyle == null) {
+ throw new IllegalArgumentException("--bigtext requires --style bigtext");
+ }
+ bigTextStyle.bigText(getNextArgRequired());
+ break;
+ case "--picture":
+ if (bigPictureStyle == null) {
+ throw new IllegalArgumentException("--picture requires --style bigpicture");
+ }
+ final String pictureSpec = getNextArgRequired();
+ final Icon pictureAsIcon = parseIcon(res, pictureSpec);
+ if (pictureAsIcon == null) {
+ throw new IllegalArgumentException("bad picture spec: " + pictureSpec);
+ }
+ final Drawable d = pictureAsIcon.loadDrawable(context);
+ if (d instanceof BitmapDrawable) {
+ bigPictureStyle.bigPicture(((BitmapDrawable) d).getBitmap());
+ } else {
+ throw new IllegalArgumentException("not a bitmap: " + pictureSpec);
+ }
+ break;
+ case "--line":
+ if (inboxStyle == null) {
+ throw new IllegalArgumentException("--line requires --style inbox");
+ }
+ inboxStyle.addLine(getNextArgRequired());
+ break;
+ case "--message":
+ if (messagingStyle == null) {
+ throw new IllegalArgumentException(
+ "--message requires --style messaging");
+ }
+ String arg = getNextArgRequired();
+ String[] parts = arg.split(":", 2);
+ if (parts.length > 1) {
+ messagingStyle.addMessage(parts[1], System.currentTimeMillis(),
+ parts[0]);
+ } else {
+ messagingStyle.addMessage(parts[0], System.currentTimeMillis(),
+ new String[]{
+ messagingStyle.getUserDisplayName().toString(),
+ "Them"
+ }[messagingStyle.getMessages().size() % 2]);
+ }
+ break;
+ case "--conversation":
+ if (messagingStyle == null) {
+ throw new IllegalArgumentException(
+ "--conversation requires --style messaging");
+ }
+ messagingStyle.setConversationTitle(getNextArgRequired());
+ break;
+ case "-h":
+ case "--help":
+ case "--wtf":
+ default:
+ pw.println(NOTIFY_USAGE);
+ return 0;
+ }
+ }
+
+ final String tag = getNextArg();
+ final String text = getNextArg();
+ if (tag == null || text == null) {
+ pw.println(NOTIFY_USAGE);
+ return -1;
+ }
+
+ builder.setContentText(text);
+
+ if (smallIcon == null) {
+ // uh oh, let's substitute something
+ builder.setSmallIcon(com.android.internal.R.drawable.stat_notify_chat);
+ } else {
+ builder.setSmallIcon(smallIcon);
+ }
+
+ ensureChannel();
+
+ final Notification n = builder.build();
+ pw.println("posting:\n " + n);
+ Slog.v("NotificationManager", "posting: " + n);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mBinderService.enqueueNotificationWithTag(
+ NOTIFICATION_PACKAGE, "android",
+ tag, NOTIFICATION_ID,
+ n, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ if (verbose) {
+ NotificationRecord nr = mDirectService.findNotificationLocked(
+ NOTIFICATION_PACKAGE, tag, NOTIFICATION_ID, userId);
+ for (int tries = 3; tries-- > 0; ) {
+ if (nr != null) break;
+ try {
+ pw.println("waiting for notification to post...");
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ }
+ nr = mDirectService.findNotificationLocked(
+ NOTIFICATION_PACKAGE, tag, NOTIFICATION_ID, userId);
+ }
+ if (nr == null) {
+ pw.println("warning: couldn't find notification after enqueueing");
+ } else {
+ pw.println("posted: ");
+ nr.dump(pw, " ", context, false);
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().println(USAGE);
+ }
+}
+
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index ee067460cc45..2b4ec03b98fd 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -179,13 +179,19 @@ final class OverlayManagerSettings {
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) {
+ // Static RROs targeting "android" are loaded from AssetManager, and so they should be
+ // ignored in OverlayManagerService.
return selectWhereTarget(targetPackageName, userId)
+ .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
.map(SettingsItem::getOverlayInfo)
.collect(Collectors.toList());
}
ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
+ // Static RROs targeting "android" are loaded from AssetManager, and so they should be
+ // ignored in OverlayManagerService.
return selectWhereUser(userId)
+ .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName())))
.map(SettingsItem::getOverlayInfo)
.collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new,
Collectors.toList()));
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 886cfb25eadd..642bfa2e70fd 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -24,8 +24,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
@@ -91,7 +91,7 @@ public class ModuleInfoProvider {
final PackageInfo pi;
try {
pi = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_META_DATA, Process.SYSTEM_UID);
+ PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
Context packageContext = mContext.createPackageContext(packageName, 0);
packageResources = packageContext.getResources();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e038f9b606bc..7ca39df39bb7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -128,6 +128,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private final Context mContext;
private final PackageManagerService mPm;
+ private final StagingManager mStagingManager;
private final PermissionManagerInternal mPermissionManager;
private AppOpsManager mAppOps;
@@ -163,12 +164,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@GuardedBy("mSessions")
private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
- // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable
- // shouldn't be needed at all.
- // TODO(b/118865310): Implement staged sessions logic.
- @GuardedBy("mStagedSessions")
- private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
-
/** Historical sessions kept around for debugging purposes */
@GuardedBy("mSessions")
private final List<String> mHistoricalSessions = new ArrayList<>();
@@ -204,6 +199,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
"package-session");
mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
+
+ mStagingManager = new StagingManager(pm);
}
public void systemReady() {
@@ -212,8 +209,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
synchronized (mSessions) {
readSessionsLocked();
- reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
- reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
+ reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
final ArraySet<File> unclaimedIcons = newArraySet(
mSessionsDir.listFiles());
@@ -233,8 +229,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
@GuardedBy("mSessions")
- private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
- final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
+ private void reconcileStagesLocked(String volumeUuid) {
+ final File stagingDir = getTmpSessionDir(volumeUuid);
final ArraySet<File> unclaimedStages = newArraySet(
stagingDir.listFiles(sStageFilter));
@@ -255,7 +251,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
public void onPrivateVolumeMounted(String volumeUuid) {
synchronized (mSessions) {
- reconcileStagesLocked(volumeUuid, false /*isInstant*/);
+ reconcileStagesLocked(volumeUuid);
}
}
@@ -272,9 +268,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
try {
final int sessionId = allocateSessionIdLocked();
mLegacySessions.put(sessionId, true);
- final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
- prepareStageDir(stageDir);
- return stageDir;
+ final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
+ prepareStageDir(sessionStageDir);
+ return sessionStageDir;
} catch (IllegalStateException e) {
throw new IOException(e);
}
@@ -311,7 +307,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
final PackageInstallerSession session;
try {
session = PackageInstallerSession.readFromXml(in, mInternalCallback,
- mContext, mPm, mInstallThread.getLooper(), mSessionsDir, this);
+ mContext, mPm, mInstallThread.getLooper(), mStagingManager,
+ mSessionsDir, this);
currentSession = session;
} catch (Exception e) {
currentSession = null;
@@ -528,25 +525,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
String stageCid = null;
if (!params.isMultiPackage) {
if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
- final boolean isInstant =
- (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
- stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
+ stageDir = buildSessionDir(sessionId, params);
} else {
stageCid = buildExternalStageCid(sessionId);
}
}
session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
- mInstallThread.getLooper(), sessionId, userId, installerPackageName,
- callingUid, params, createdMillis, stageDir, stageCid, false, false, null,
- SessionInfo.INVALID_ID);
+ mInstallThread.getLooper(), mStagingManager, sessionId, userId,
+ installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
+ false, null, SessionInfo.INVALID_ID);
synchronized (mSessions) {
mSessions.put(sessionId, session);
}
if (params.isStaged) {
- synchronized (mStagedSessions) {
- mStagedSessions.put(sessionId, session);
- }
+ mStagingManager.createSession(session);
}
mCallbacks.notifySessionCreated(session.sessionId, session.userId);
@@ -638,13 +631,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new IllegalStateException("Failed to allocate session ID");
}
- private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
+ private File getTmpSessionDir(String volumeUuid) {
return Environment.getDataAppDirectory(volumeUuid);
}
- private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
- final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
- return new File(stagingDir, "vmdl" + sessionId + ".tmp");
+ private File buildTmpSessionDir(int sessionId, String volumeUuid) {
+ final File sessionStagingDir = getTmpSessionDir(volumeUuid);
+ return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
+ }
+
+ private File buildSessionDir(int sessionId, SessionParams params) {
+ if (params.isStaged) {
+ final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
+ return new File(sessionStagingDir, "session_" + sessionId);
+ }
+ return buildTmpSessionDir(sessionId, params.volumeUuid);
}
static void prepareStageDir(File stageDir) throws IOException {
@@ -679,14 +680,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@Override
public ParceledListSlice<SessionInfo> getStagedSessions() {
- final List<SessionInfo> result = new ArrayList<>();
- synchronized (mStagedSessions) {
- for (int i = 0; i < mStagedSessions.size(); i++) {
- final PackageInstallerSession session = mStagedSessions.valueAt(i);
- result.add(session.generateInfo(false));
- }
- }
- return new ParceledListSlice<>(result);
+ return mStagingManager.getSessions();
}
@Override
@@ -1131,16 +1125,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mInstallHandler.post(new Runnable() {
@Override
public void run() {
- // TODO(b/118865310): remove this mock implementation.
if (session.isStaged()) {
- // If the session is aborted, don't keep it in memory. Only store
- // sessions successfully staged.
if (!success) {
- synchronized (mStagedSessions) {
- mStagedSessions.remove(session.sessionId);
- }
- } else {
- return;
+ mStagingManager.abortSession(session);
}
}
synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 35ffe8d5fa95..982daa5df2d5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -105,6 +106,8 @@ import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.security.VerityUtils;
import libcore.io.IoUtils;
@@ -174,6 +177,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final PackageManagerService mPm;
private final Handler mHandler;
private final PackageSessionProvider mSessionProvider;
+ private final StagingManager mStagingManager;
final int sessionId;
final int userId;
@@ -283,6 +287,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
@GuardedBy("mLock")
private File mInheritedFilesBase;
+ @GuardedBy("mLock")
+ private boolean mVerityFound;
private static final FileFilter sAddedFilter = new FileFilter() {
@Override
@@ -292,6 +298,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (file.isDirectory()) return false;
if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
if (DexMetadataHelper.isDexMetadataFile(file)) return false;
+ if (VerityUtils.isFsveritySignatureFile(file)) return false;
return true;
}
};
@@ -396,7 +403,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Context context, PackageManagerService pm,
- PackageSessionProvider sessionProvider, Looper looper,
+ PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
int sessionId, int userId,
String installerPackageName, int installerUid, SessionParams params, long createdMillis,
File stageDir, String stageCid, boolean prepared, boolean sealed,
@@ -406,6 +413,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mPm = pm;
mSessionProvider = sessionProvider;
mHandler = new Handler(looper, mHandlerCallback);
+ mStagingManager = stagingManager;
this.sessionId = sessionId;
this.userId = userId;
@@ -699,9 +707,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
switch (Binder.getCallingUid()) {
case android.os.Process.SHELL_UID:
case android.os.Process.ROOT_UID:
+ case android.os.Process.SYSTEM_UID:
break;
default:
- throw new SecurityException("Reverse mode only supported from shell");
+ throw new SecurityException(
+ "Reverse mode only supported from shell or system");
}
// In "reverse" mode, we're streaming data ourselves from the
@@ -973,18 +983,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information.
- if (!params.isMultiPackage) {
+ // For staged sessions, the validation is performed by StagingManager.
+ if (!params.isMultiPackage && !params.isStaged) {
final PackageInfo pkgInfo = mPm.getPackageInfo(
params.appPackageName, PackageManager.GET_SIGNATURES
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
resolveStageDirLocked();
- // Verify that stage looks sane with respect to existing application.
- // This currently only ensures packageName, versionCode, and certificate
- // consistency.
try {
if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ // TODO(b/118865310): Remove this when APEX validation is done via
+ // StagingManager.
validateApexInstallLocked(pkgInfo);
} else {
// Verify that stage looks sane with respect to existing application.
@@ -1057,18 +1067,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private void commitLocked()
throws PackageManagerException {
+ if (params.isStaged) {
+ mStagingManager.commitSession(this);
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
+ return;
+ }
final PackageManagerService.ActiveInstallSession committingSession =
makeSessionActiveLocked();
if (committingSession == null) {
return;
}
- if (isStaged()) {
- // STOPSHIP: implement staged sessions
- mStagedSessionReady = true;
- mPm.sendSessionUpdatedBroadcast(generateInfo(), userId);
- dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
- return;
- }
if (isMultiPackage()) {
final int[] childSessionIds = getChildSessionIds();
List<PackageManagerService.ActiveInstallSession> childSessions =
@@ -1083,7 +1092,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (activeSession != null) {
if ((activeSession.getSessionParams().installFlags
& PackageManager.INSTALL_APEX) != 0) {
- // TODO(b/118865310): Add exception to this case for staged installs
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Atomic install is not supported for APEX packages.");
@@ -1359,6 +1367,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
+ // Partial installs must be consistent with existing install
+ if (params.mode == SessionParams.MODE_INHERIT_EXISTING
+ && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Missing existing base package");
+ }
+ // Default to require only if existing base has fs-verity.
+ mVerityFound = params.mode == SessionParams.MODE_INHERIT_EXISTING
+ && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
+
try {
resolveStageDirLocked();
} catch (IOException e) {
@@ -1422,7 +1440,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetFile = new File(mResolvedStageDir, targetName);
- maybeRenameFile(addedFile, targetFile);
+ resolveAndStageFile(addedFile, targetFile);
// Base is coming from session
if (apk.splitName == null) {
@@ -1430,8 +1448,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
baseApk = apk;
}
- mResolvedStagedFiles.add(targetFile);
-
final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
if (dexMetadataFile != null) {
if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
@@ -1440,8 +1456,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetDexMetadataFile = new File(mResolvedStageDir,
DexMetadataHelper.buildDexMetadataPathForApk(targetName));
- mResolvedStagedFiles.add(targetDexMetadataFile);
- maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
+ resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
}
}
@@ -1484,12 +1499,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
} else {
- // Partial installs must be consistent with existing install
- if (pkgInfo == null || pkgInfo.applicationInfo == null) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Missing existing base package for " + mPackageName);
- }
-
final PackageLite existing;
final ApkLite existingBase;
ApplicationInfo appInfo = pkgInfo.applicationInfo;
@@ -1593,12 +1602,55 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
}
+ if (baseApk.preferCodeIntegrity) {
+ for (File file : mResolvedStagedFiles) {
+ if (file.getName().endsWith(".apk")
+ && !DexManager.auditUncompressedCodeInApk(file.getPath())) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Some code are not uncompressed and aligned correctly for "
+ + mPackageName);
+ }
+ }
+ }
if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}
}
+ private void resolveAndStageFile(File origFile, File targetFile)
+ throws PackageManagerException {
+ mResolvedStagedFiles.add(targetFile);
+ maybeRenameFile(origFile, targetFile);
+
+ final File originalSignature = new File(
+ VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
+ // Make sure .fsv_sig exists when it should, then resolve and stage it.
+ if (originalSignature.exists()) {
+ // mVerityFound can only change from false to true here during the staging loop. Since
+ // all or none of files should have .fsv_sig, this should only happen in the first time
+ // (or never), otherwise bail out.
+ if (!mVerityFound) {
+ mVerityFound = true;
+ if (mResolvedStagedFiles.size() > 1) {
+ throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
+ "Some file is missing fs-verity signature");
+ }
+ }
+ } else {
+ if (!mVerityFound) {
+ return;
+ }
+ throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
+ "Missing corresponding fs-verity signature to " + origFile);
+ }
+
+ final File stagedSignature = new File(
+ VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
+ maybeRenameFile(originalSignature, stagedSignature);
+ mResolvedStagedFiles.add(stagedSignature);
+ }
+
@GuardedBy("mLock")
private void assertApkConsistentLocked(String tag, ApkLite apk)
throws PackageManagerException {
@@ -1950,6 +2002,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mCallback.onSessionFinished(this, success);
}
+ void setStagedSessionReady() {
+ synchronized (mLock) {
+ mStagedSessionReady = true;
+ mStagedSessionApplied = false;
+ mStagedSessionFailed = false;
+ mStagedSessionErrorCode = SessionInfo.NO_ERROR;
+ }
+ }
+
private void destroyInternal() {
synchronized (mLock) {
mSealed = true;
@@ -1963,7 +2024,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
bridge.forceClose();
}
}
- if (stageDir != null) {
+ // 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.
+ if (stageDir != null && !params.isStaged) {
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -2151,7 +2216,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// can have a complete session for the constructor
public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
@NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
- @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir,
+ @NonNull PackageManagerService pm, Looper installerThread,
+ @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
@NonNull PackageSessionProvider sessionProvider)
throws IOException, XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
@@ -2195,8 +2261,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
params.appIconLastModified = appIconFile.lastModified();
}
return new PackageInstallerSession(callback, context, pm, sessionProvider,
- installerThread, sessionId, userId, installerPackageName, installerUid,
- params, createdMillis, stageDir, stageCid, prepared, sealed,
+ installerThread, stagingManager, sessionId, userId, installerPackageName,
+ installerUid, params, createdMillis, stageDir, stageCid, prepared, sealed,
EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2ef331558588..fe89be6f73c4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -296,6 +296,7 @@ import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
+import com.android.server.PackageWatchdog;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
@@ -546,6 +547,12 @@ public class PackageManagerService extends IPackageManager.Stub
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
+ * The default duration to wait for rollback to be enabled in
+ * milliseconds.
+ */
+ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000;
+
+ /**
* The default response for package verification timeout.
*
* This can be either PackageManager.VERIFICATION_ALLOW or
@@ -865,6 +872,9 @@ public class PackageManagerService extends IPackageManager.Stub
/** List of packages waiting for verification. */
final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
+ /** List of packages waiting for rollback to be enabled. */
+ final SparseArray<InstallParams> mPendingEnableRollback = new SparseArray<>();
+
final PackageInstallerService mInstallerService;
final ArtManagerService mArtManagerService;
@@ -885,6 +895,9 @@ public class PackageManagerService extends IPackageManager.Stub
/** Token for keys in mPendingVerification. */
private int mPendingVerificationToken = 0;
+ /** Token for keys in mPendingEnableRollback. */
+ private int mPendingEnableRollbackToken = 0;
+
volatile boolean mSystemReady;
volatile boolean mSafeMode;
volatile boolean mHasSystemUidErrors;
@@ -1256,6 +1269,8 @@ public class PackageManagerService extends IPackageManager.Stub
static final int INTENT_FILTER_VERIFIED = 18;
static final int WRITE_PACKAGE_LIST = 19;
static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
+ static final int ENABLE_ROLLBACK_STATUS = 21;
+ static final int ENABLE_ROLLBACK_TIMEOUT = 22;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
@@ -1479,14 +1494,13 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageVerificationState state = mPendingVerification.get(verificationId);
if ((state != null) && !state.timeoutExtended()) {
- final InstallArgs args = state.getInstallArgs();
+ final InstallParams params = state.getInstallParams();
+ final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
mPendingVerification.remove(verificationId);
- int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
-
final UserHandle user = args.getUser();
if (getDefaultVerificationResponse(user)
== PackageManager.VERIFICATION_ALLOW) {
@@ -1495,16 +1509,16 @@ public class PackageManagerService extends IPackageManager.Stub
PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, user);
- ret = args.copyApk();
} else {
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_REJECT, user);
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
-
- processPendingInstall(args, ret);
+ params.handleVerificationFinished();
}
break;
}
@@ -1524,22 +1538,22 @@ public class PackageManagerService extends IPackageManager.Stub
if (state.isVerificationComplete()) {
mPendingVerification.remove(verificationId);
- final InstallArgs args = state.getInstallArgs();
+ final InstallParams params = state.getInstallParams();
+ final InstallArgs args = params.mArgs;
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
- int ret;
if (state.isInstallAllowed()) {
broadcastPackageVerified(verificationId, originUri,
- response.code, state.getInstallArgs().getUser());
- ret = args.copyApk();
+ response.code, args.getUser());
} else {
- ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
+ params.setReturnCode(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE);
}
Trace.asyncTraceEnd(
TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
- processPendingInstall(args, ret);
+ params.handleVerificationFinished();
}
break;
@@ -1599,6 +1613,49 @@ public class PackageManagerService extends IPackageManager.Stub
(InstantAppRequest) msg.obj,
mInstantAppInstallerActivity,
mHandler);
+ break;
+ }
+ case ENABLE_ROLLBACK_STATUS: {
+ final int enableRollbackToken = msg.arg1;
+ final int enableRollbackCode = msg.arg2;
+ InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ if (params == null) {
+ Slog.w(TAG, "Invalid rollback enabled token "
+ + enableRollbackToken + " received");
+ break;
+ }
+
+ mPendingEnableRollback.remove(enableRollbackToken);
+
+ if (enableRollbackCode != PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED) {
+ final InstallArgs args = params.mArgs;
+ final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+ Slog.w(TAG, "Failed to enable rollback for " + originUri);
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ }
+
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+
+ params.handleRollbackEnabled();
+ break;
+ }
+ case ENABLE_ROLLBACK_TIMEOUT: {
+ final int enableRollbackToken = msg.arg1;
+ final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ if (params != null) {
+ final InstallArgs args = params.mArgs;
+ final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
+
+ Slog.w(TAG, "Enable rollback timed out for " + originUri);
+ mPendingEnableRollback.remove(enableRollbackToken);
+
+ Slog.w(TAG, "Continuing with installation of " + originUri);
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ params.handleRollbackEnabled();
+ }
+ break;
}
}
}
@@ -8492,16 +8549,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * Returns if full apk verification can be skipped for the whole package, including the splits.
+ * Returns if forced apk verification can be skipped for the whole package, including splits.
*/
- private boolean canSkipFullPackageVerification(PackageParser.Package pkg) {
- if (!canSkipFullApkVerification(pkg.baseCodePath)) {
+ private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
+ if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
return false;
}
// TODO: Allow base and splits to be verified individually.
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- if (!canSkipFullApkVerification(pkg.splitCodePaths[i])) {
+ if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
return false;
}
}
@@ -8510,14 +8567,17 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * Returns if full apk verification can be skipped, depending on current FSVerity setup and
+ * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
* whether the apk contains signed root hash. Note that the signer's certificate still needs to
* match one in a trusted source, and should be done separately.
*/
- private boolean canSkipFullApkVerification(String apkPath) {
- final byte[] rootHashObserved;
+ private boolean canSkipForcedApkVerification(String apkPath) {
+ if (!PackageManagerServiceUtils.isLegacyApkVerityMode()) {
+ return VerityUtils.hasFsverity(apkPath);
+ }
+
try {
- rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
+ final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
if (rootHashObserved == null) {
return false; // APK does not contain Merkle tree root hash.
}
@@ -8689,7 +8749,7 @@ public class PackageManagerService extends IPackageManager.Stub
// in verified partition, or can be verified on access (when apk verity is enabled). In both
// cases, only data in Signing Block is verified instead of the whole file.
final boolean skipVerify = scanSystemPartition
- || (forceCollect && canSkipFullPackageVerification(pkg));
+ || (forceCollect && canSkipForcedPackageVerification(pkg));
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
// Reset profile if the application version is changed
@@ -9436,6 +9496,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageUsage.writeNow(mPackages);
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
+ PackageWatchdog.getInstance(mContext).writeNow();
// This is the last chance to write out pending restriction settings
synchronized (mPackages) {
@@ -12965,20 +13026,26 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean canSuspendPackageForUser(String packageName, int userId) {
+ public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "canSuspendPackageForUser");
+ "getUnsuspendablePackagesForUser");
final int callingUid = Binder.getCallingUid();
if (UserHandle.getUserId(callingUid) != userId) {
throw new SecurityException("Calling uid " + callingUid
- + " cannot query canSuspendPackageForUser for user " + userId);
+ + " cannot query getUnsuspendablePackagesForUser for user " + userId);
}
+ final ArraySet<String> unactionablePackages = new ArraySet<>();
final long identity = Binder.clearCallingIdentity();
try {
- return canSuspendPackageForUserInternal(packageName, userId);
+ for (String packageName : packageNames) {
+ if (!canSuspendPackageForUserInternal(packageName, userId)) {
+ unactionablePackages.add(packageName);
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
+ return unactionablePackages.toArray(new String[unactionablePackages.size()]);
}
private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
@@ -13223,6 +13290,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ private void setEnableRollbackCode(int token, int enableRollbackCode) {
+ final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
+ msg.arg1 = token;
+ msg.arg2 = enableRollbackCode;
+ mHandler.sendMessage(msg);
+ }
+
@Override
public void finishPackageInstall(int token, boolean didLaunch) {
enforceSystemOrRoot("Only the system is allowed to finish installs");
@@ -13874,7 +13948,7 @@ public class PackageManagerService extends IPackageManager.Stub
@NonNull
private final ArrayList<InstallParams> mChildParams;
@NonNull
- private final Map<InstallArgs, Integer> mVerifiedState;
+ private final Map<InstallArgs, Integer> mCurrentState;
MultiPackageInstallParams(
@NonNull UserHandle user,
@@ -13890,7 +13964,7 @@ public class PackageManagerService extends IPackageManager.Stub
childParams.mParentInstallParams = this;
this.mChildParams.add(childParams);
}
- this.mVerifiedState = new ArrayMap<>(mChildParams.size());
+ this.mCurrentState = new ArrayMap<>(mChildParams.size());
}
@Override
@@ -13916,12 +13990,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
- mVerifiedState.put(args, currentStatus);
+ mCurrentState.put(args, currentStatus);
boolean success = true;
- if (mVerifiedState.size() != mChildParams.size()) {
+ if (mCurrentState.size() != mChildParams.size()) {
return;
}
- for (Integer status : mVerifiedState.values()) {
+ for (Integer status : mCurrentState.values()) {
if (status == PackageManager.INSTALL_UNKNOWN) {
return;
} else if (status != PackageManager.INSTALL_SUCCEEDED) {
@@ -13929,8 +14003,8 @@ public class PackageManagerService extends IPackageManager.Stub
break;
}
}
- final List<InstallRequest> installRequests = new ArrayList<>(mVerifiedState.size());
- for (Map.Entry<InstallArgs, Integer> entry : mVerifiedState.entrySet()) {
+ final List<InstallRequest> installRequests = new ArrayList<>(mCurrentState.size());
+ for (Map.Entry<InstallArgs, Integer> entry : mCurrentState.entrySet()) {
installRequests.add(new InstallRequest(entry.getKey(),
createPackageInstalledInfo(entry.getValue())));
}
@@ -13947,6 +14021,8 @@ public class PackageManagerService extends IPackageManager.Stub
int installFlags;
final String installerPackageName;
final String volumeUuid;
+ private boolean mVerificationCompleted;
+ private boolean mEnableRollbackCompleted;
private InstallArgs mArgs;
int mRet;
final String packageAbiOverride;
@@ -14196,6 +14272,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
final InstallArgs args = createInstallArgs(this);
+ mVerificationCompleted = true;
+ mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
@@ -14275,7 +14353,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final PackageVerificationState verificationState = new PackageVerificationState(
- requiredUid, args);
+ requiredUid, this);
mPendingVerification.append(verificationId, verificationState);
@@ -14337,25 +14415,80 @@ public class PackageManagerService extends IPackageManager.Stub
/*
* We don't want the copy to proceed until verification
- * succeeds, so null out this field.
+ * succeeds.
*/
- mArgs = null;
+ mVerificationCompleted = false;
}
- } else {
- /*
- * No package verification is enabled, so immediately start
- * the remote call to initiate copy using temporary file.
- */
- ret = args.copyApk();
+ }
+
+ if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+ // TODO(ruhler) b/112431924: Don't do this in case of 'move'?
+ final int enableRollbackToken = mPendingEnableRollbackToken++;
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
+ mPendingEnableRollback.append(enableRollbackToken, this);
+
+ // TODO(ruhler) b/112431924: What user? Test for multi-user.
+ Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
+ enableRollbackToken);
+ enableRollbackIntent.putExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
+ installFlags);
+ enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
+ PACKAGE_MIME_TYPE);
+ enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, getUser(),
+ android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // TODO(ruhler) b/112431924 Have a configurable setting to
+ // allow changing the timeout and fall back to the default
+ // if no such specified.
+ final Message msg = mHandler.obtainMessage(
+ ENABLE_ROLLBACK_TIMEOUT);
+ msg.arg1 = enableRollbackToken;
+ mHandler.sendMessageDelayed(msg,
+ DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+ }
+ }, null, 0, null, null);
+
+ mEnableRollbackCompleted = false;
}
}
mRet = ret;
}
+ void setReturnCode(int ret) {
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ // Only update mRet if it was previously INSTALL_SUCCEEDED to
+ // ensure we do not overwrite any previous failure results.
+ mRet = ret;
+ }
+ }
+
+ void handleVerificationFinished() {
+ mVerificationCompleted = true;
+ handleReturnCode();
+ }
+
+ void handleRollbackEnabled() {
+ // TODO(ruhler) b/112431924: Consider halting the install if we
+ // couldn't enable rollback.
+ mEnableRollbackCompleted = true;
+ handleReturnCode();
+ }
+
@Override
void handleReturnCode() {
- if (mArgs != null) {
+ if (mVerificationCompleted && mEnableRollbackCompleted) {
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ mRet = mArgs.copyApk();
+ }
processPendingInstall(mArgs, mRet);
}
}
@@ -16422,44 +16555,11 @@ public class PackageManagerService extends IPackageManager.Stub
throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
}
- if (PackageManagerServiceUtils.isApkVerityEnabled()) {
- String apkPath = null;
- synchronized (mPackages) {
- // Note that if the attacker managed to skip verify setup, for example by tampering
- // with the package settings, upon reboot we will do full apk verification when
- // verity is not detected.
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null && ps.isPrivileged()) {
- apkPath = pkg.baseCodePath;
- }
- }
- if (apkPath != null) {
- final VerityUtils.SetupResult result =
- VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */,
- true /* skipSigningBlock */);
- if (result.isOk()) {
- if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
- FileDescriptor fd = result.getUnownedFileDescriptor();
- try {
- final byte[] signedRootHash =
- VerityUtils.generateApkVerityRootHash(apkPath);
- mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
- mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
- } catch (InstallerException | IOException | DigestException |
- NoSuchAlgorithmException e) {
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to set up verity: " + e);
- } finally {
- IoUtils.closeQuietly(fd);
- }
- } else if (result.isFailed()) {
- throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to generate verity");
- } else {
- // Do nothing if verity is skipped. Will fall back to full apk verification on
- // reboot.
- }
- }
+ try {
+ setUpFsVerityIfPossible(pkg);
+ } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
+ throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to set up verity: " + e);
}
if (!instantApp) {
@@ -16757,6 +16857,85 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ /**
+ * Set up fs-verity for the given package if possible. This requires a feature flag of system
+ * property to be enabled only if the kernel supports fs-verity.
+ *
+ * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
+ * kernel patches). In normal mode, all file format can be supported.
+ */
+ private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+ PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
+ if (!PackageManagerServiceUtils.isApkVerityEnabled()) {
+ return;
+ }
+ final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityMode();
+
+ // Collect files we care for fs-verity setup.
+ ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
+ if (legacyMode) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+ if (ps != null && ps.isPrivileged()) {
+ fsverityCandidates.put(pkg.baseCodePath, null);
+ if (pkg.splitCodePaths != null) {
+ for (String splitPath : pkg.splitCodePaths) {
+ fsverityCandidates.put(splitPath, null);
+ }
+ }
+ }
+ }
+ } else {
+ // NB: These files will become only accessible if the signing key is loaded in kernel's
+ // .fs-verity keyring.
+ fsverityCandidates.put(pkg.baseCodePath,
+ VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+
+ final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+ if (new File(dmPath).exists()) {
+ fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
+ }
+
+ if (pkg.splitCodePaths != null) {
+ for (String path : pkg.splitCodePaths) {
+ fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
+
+ final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
+ if (new File(splitDmPath).exists()) {
+ fsverityCandidates.put(splitDmPath,
+ VerityUtils.getFsveritySignatureFilePath(splitDmPath));
+ }
+ }
+ }
+ }
+
+ for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
+ final String filePath = entry.getKey();
+ final String signaturePath = entry.getValue();
+
+ final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(
+ filePath, signaturePath, legacyMode);
+ if (result.isOk()) {
+ if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
+ final FileDescriptor fd = result.getUnownedFileDescriptor();
+ try {
+ mInstaller.installApkVerity(filePath, fd, result.getContentSize());
+
+ // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+ if (legacyMode) {
+ final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+ mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+ }
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else if (result.isFailed()) {
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+ "Failed to generate verity");
+ }
+ }
+ }
+
private void startIntentFilterVerifications(int userId, boolean replacing,
PackageParser.Package pkg) {
if (mIntentFilterVerifierComponent == null) {
@@ -23462,6 +23641,11 @@ public class PackageManagerService extends IPackageManager.Stub
return setting.getEnabled(userId);
}
}
+
+ @Override
+ public void setEnableRollbackCode(int token, int enableRollbackCode) {
+ PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode);
+ }
}
@GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 36948fce4655..25169a24d932 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -543,9 +543,26 @@ public class PackageManagerServiceUtils {
}
}
+ /** Default is to not use fs-verity since it depends on kernel support. */
+ private static final int FSVERITY_DISABLED = 0;
+
+ /**
+ * Experimental implementation targeting priv apps, with Android specific kernel patches to
+ * extend fs-verity.
+ */
+ private static final int FSVERITY_LEGACY = 1;
+
+ /** Standard fs-verity. */
+ private static final int FSVERITY_ENABLED = 2;
+
/** Returns true if APK Verity is enabled. */
static boolean isApkVerityEnabled() {
- return SystemProperties.getInt("ro.apk_verity.mode", 0) != 0;
+ int mode = SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED);
+ return mode == FSVERITY_LEGACY || mode == FSVERITY_ENABLED;
+ }
+
+ static boolean isLegacyApkVerityMode() {
+ return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY;
}
/** Returns true to force apk verification if the updated package (in /data) is a priv app. */
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 357872ef3321..2e9d26a0a0ca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2293,6 +2293,9 @@ class PackageManagerShellCommand extends ShellCommand {
break;
case "--apex":
sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+ // TODO(b/118865310): APEX packages should always imply
+ // sessionParams.isStaged(). Enforce this when the staged
+ // install workflow is complete.
break;
case "--multi-package":
sessionParams.setMultiPackage();
@@ -2300,6 +2303,9 @@ class PackageManagerShellCommand extends ShellCommand {
case "--staged":
sessionParams.setStaged();
break;
+ case "--enable-rollback":
+ sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
@@ -2585,7 +2591,7 @@ class PackageManagerShellCommand extends ShellCommand {
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
- if (!session.isMultiPackage()) {
+ if (!session.isMultiPackage() && !session.isStaged()) {
// Sanity check that all .dm files match an apk.
// (The installer does not support standalone .dm files and will not process them.)
try {
@@ -2833,6 +2839,7 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println(" [--install-reason 0/1/2/3/4] [--originating-uri URI]");
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
+ pw.println(" [--enable-rollback]");
pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [--apex]");
pw.println(" [PATH|-]");
pw.println(" Install an application. Must provide the apk data to install, either as a");
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index 3214e8895fd5..c50bf59f0206 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -16,11 +16,11 @@
package com.android.server.pm;
-import com.android.server.pm.PackageManagerService.InstallArgs;
-
import android.content.pm.PackageManager;
import android.util.SparseBooleanArray;
+import com.android.server.pm.PackageManagerService.InstallParams;
+
/**
* Tracks the package verification state for a particular package. Each package
* verification has a required verifier and zero or more sufficient verifiers.
@@ -29,7 +29,7 @@ import android.util.SparseBooleanArray;
* then package verification is considered complete.
*/
class PackageVerificationState {
- private final InstallArgs mArgs;
+ private final InstallParams mParams;
private final SparseBooleanArray mSufficientVerifierUids;
@@ -53,15 +53,15 @@ class PackageVerificationState {
* @param requiredVerifierUid user ID of required package verifier
* @param args
*/
- public PackageVerificationState(int requiredVerifierUid, InstallArgs args) {
+ PackageVerificationState(int requiredVerifierUid, InstallParams params) {
mRequiredVerifierUid = requiredVerifierUid;
- mArgs = args;
+ mParams = params;
mSufficientVerifierUids = new SparseBooleanArray();
mExtendedTimeout = false;
}
- public InstallArgs getInstallArgs() {
- return mArgs;
+ InstallParams getInstallParams() {
+ return mParams;
}
/**
@@ -69,7 +69,7 @@ class PackageVerificationState {
*
* @param uid user ID of sufficient verifier
*/
- public void addSufficientVerifier(int uid) {
+ void addSufficientVerifier(int uid) {
mSufficientVerifierUids.put(uid, true);
}
@@ -80,7 +80,7 @@ class PackageVerificationState {
* @param uid user ID of the verifying agent
* @return {@code true} if the verifying agent actually exists in our list
*/
- public boolean setVerifierResponse(int uid, int code) {
+ boolean setVerifierResponse(int uid, int code) {
if (uid == mRequiredVerifierUid) {
mRequiredVerificationComplete = true;
switch (code) {
@@ -120,7 +120,7 @@ class PackageVerificationState {
*
* @return {@code true} when verification is considered complete
*/
- public boolean isVerificationComplete() {
+ boolean isVerificationComplete() {
if (!mRequiredVerificationComplete) {
return false;
}
@@ -138,7 +138,7 @@ class PackageVerificationState {
*
* @return {@code true} if installation should be allowed
*/
- public boolean isInstallAllowed() {
+ boolean isInstallAllowed() {
if (!mRequiredVerificationPassed) {
return false;
}
@@ -153,7 +153,7 @@ class PackageVerificationState {
/**
* Extend the timeout for this Package to be verified.
*/
- public void extendTimeout() {
+ void extendTimeout() {
if (!mExtendedTimeout) {
mExtendedTimeout = true;
}
@@ -164,7 +164,7 @@ class PackageVerificationState {
*
* @return {@code true} if a timeout was already extended.
*/
- public boolean timeoutExtended() {
+ boolean timeoutExtended() {
return mExtendedTimeout;
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
new file mode 100644
index 000000000000..3beda6a3f92b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.content.pm.PackageInstaller;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class handles staged install sessions, i.e. install sessions that require packages to
+ * be installed only after a reboot.
+ */
+public class StagingManager {
+
+ private static final String TAG = "StagingManager";
+
+ private final PackageManagerService mPm;
+ private final Handler mBgHandler;
+
+ // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable
+ // shouldn't be needed at all.
+ // TODO(b/118865310): Implement staged sessions logic.
+ @GuardedBy("mStagedSessions")
+ private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
+
+ StagingManager(PackageManagerService pm) {
+ mPm = pm;
+ mBgHandler = BackgroundThread.getHandler();
+ }
+
+ private void updateStoredSession(@NonNull PackageInstallerSession sessionInfo) {
+ synchronized (mStagedSessions) {
+ PackageInstallerSession storedSession = mStagedSessions.get(sessionInfo.sessionId);
+ // storedSession might be null if a call to abortSession was made before the session
+ // is updated.
+ if (storedSession != null) {
+ mStagedSessions.put(sessionInfo.sessionId, sessionInfo);
+ }
+ }
+ }
+
+ ParceledListSlice<PackageInstaller.SessionInfo> getSessions() {
+ final List<PackageInstaller.SessionInfo> result = new ArrayList<>();
+ synchronized (mStagedSessions) {
+ for (int i = 0; i < mStagedSessions.size(); i++) {
+ result.add(mStagedSessions.valueAt(i).generateInfo(false));
+ }
+ }
+ return new ParceledListSlice<>(result);
+ }
+
+ void commitSession(@NonNull PackageInstallerSession sessionInfo) {
+ updateStoredSession(sessionInfo);
+
+ mBgHandler.post(() -> {
+ // TODO(b/118865310): Dispatch the session to apexd/PackageManager for verification. For
+ // now we directly mark it as ready.
+ sessionInfo.setStagedSessionReady();
+ mPm.sendSessionUpdatedBroadcast(sessionInfo.generateInfo(), sessionInfo.userId);
+ });
+ }
+
+ void createSession(@NonNull PackageInstallerSession sessionInfo) {
+ synchronized (mStagedSessions) {
+ mStagedSessions.append(sessionInfo.sessionId, sessionInfo);
+ }
+ }
+
+ void abortSession(@NonNull PackageInstallerSession sessionInfo) {
+ updateStoredSession(sessionInfo);
+ synchronized (mStagedSessions) {
+ mStagedSessions.remove(sessionInfo.sessionId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 25ef7675e2b9..e57d9d7ab61c 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -785,10 +785,10 @@ public class DexManager {
* files that can be direclty mapped.
*/
private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
- logIfApkHasUncompressedCode(pkg.baseCodePath);
+ auditUncompressedCodeInApk(pkg.baseCodePath);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- logIfApkHasUncompressedCode(pkg.splitCodePaths[i]);
+ auditUncompressedCodeInApk(pkg.splitCodePaths[i]);
}
}
}
@@ -797,34 +797,41 @@ public class DexManager {
* Generates log if the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
*/
- private static void logIfApkHasUncompressedCode(String fileName) {
+ public static boolean auditUncompressedCodeInApk(String fileName) {
StrictJarFile jarFile = null;
try {
jarFile = new StrictJarFile(fileName,
false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
Iterator<ZipEntry> it = jarFile.iterator();
+ boolean allCorrect = true;
while (it.hasNext()) {
ZipEntry entry = it.next();
if (entry.getName().endsWith(".dex")) {
if (entry.getMethod() != ZipEntry.STORED) {
+ allCorrect = false;
Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
entry.getName());
} else if ((entry.getDataOffset() & 0x3) != 0) {
+ allCorrect = false;
Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
entry.getName());
}
} else if (entry.getName().endsWith(".so")) {
if (entry.getMethod() != ZipEntry.STORED) {
+ allCorrect = false;
Slog.w(TAG, "APK " + fileName + " has compressed native code " +
entry.getName());
} else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+ allCorrect = false;
Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
entry.getName());
}
}
}
+ return allCorrect;
} catch (IOException ignore) {
Slog.wtf(TAG, "Error when parsing APK " + fileName);
+ return false;
} finally {
try {
if (jarFile != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f370edf50708..2060aef37044 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Context.DISPLAY_SERVICE;
import static android.content.Context.WINDOW_SERVICE;
+import static android.content.pm.PackageManager.FEATURE_HDMI_CEC;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -126,6 +127,7 @@ import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
+import android.hardware.hdmi.HdmiAudioSystemClient;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
@@ -195,6 +197,7 @@ import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.PhoneWindow;
@@ -373,6 +376,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private ScreenshotHelper mScreenshotHelper;
private boolean mHasFeatureWatch;
private boolean mHasFeatureLeanback;
+ private boolean mHasFeatureHdmiCec;
// Assigned on main thread, accessed on UI thread
volatile VrManagerInternal mVrManagerInternal;
@@ -844,7 +848,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void interceptBackKeyDown() {
- MetricsLogger.count(mContext, "key_back_down", 1);
+ mLogger.count("key_back_down", 1);
// Reset back key state for long press
mBackKeyHandled = false;
@@ -858,6 +862,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// returns true if the key was handled and should not be passed to the user
private boolean interceptBackKeyUp(KeyEvent event) {
+ mLogger.count("key_back_up", 1);
// Cache handled state
boolean handled = mBackKeyHandled;
@@ -1452,7 +1457,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
*/
private HdmiControl getHdmiControl() {
if (null == mHdmiControl) {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
+ if (!mHasFeatureHdmiCec) {
return null;
}
HdmiControlManager manager = (HdmiControlManager) mContext.getSystemService(
@@ -1688,6 +1693,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
+ mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
mAccessibilityShortcutController =
new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
mLogger = new MetricsLogger();
@@ -4115,6 +4121,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void dispatchDirectAudioEvent(KeyEvent event) {
+ // When System Audio Mode is off, volume keys received by AVR can be either consumed by AVR
+ // or forwarded to the TV. It's up to Amplifier manufacturer’s implementation.
+ HdmiControlManager hdmiControlManager = getHdmiControlManager();
+ if (null != hdmiControlManager
+ && !hdmiControlManager.getSystemAudioMode()
+ && shouldCecAudioDeviceForwardVolumeKeysSystemAudioModeOff()) {
+ HdmiAudioSystemClient audioSystemClient = hdmiControlManager.getAudioSystemClient();
+ if (audioSystemClient != null) {
+ audioSystemClient.sendKeyEvent(
+ event.getKeyCode(), event.getAction() == KeyEvent.ACTION_DOWN);
+ return;
+ }
+ }
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return;
}
@@ -4122,6 +4141,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND
| AudioManager.FLAG_FROM_KEY;
String pkgName = mContext.getOpPackageName();
+
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
try {
@@ -4153,6 +4173,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ @Nullable
+ private HdmiControlManager getHdmiControlManager() {
+ if (!mHasFeatureHdmiCec) {
+ return null;
+ }
+ return (HdmiControlManager) mContext.getSystemService(HdmiControlManager.class);
+ }
+
+ private boolean shouldCecAudioDeviceForwardVolumeKeysSystemAudioModeOff() {
+ return RoSystemProperties.CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF;
+ }
+
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
if (DEBUG_INPUT) {
Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
diff --git a/services/core/java/com/android/server/rollback/PackageRollbackData.java b/services/core/java/com/android/server/rollback/PackageRollbackData.java
new file mode 100644
index 000000000000..15d12427f8be
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/PackageRollbackData.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.content.rollback.PackageRollbackInfo;
+
+import java.io.File;
+import java.time.Instant;
+
+/**
+ * Information about a rollback available for a particular package.
+ * This is similar to {@link PackageRollbackInfo}, but extended with
+ * additional information for internal bookkeeping.
+ */
+class PackageRollbackData {
+ public final PackageRollbackInfo info;
+
+ /**
+ * The directory where the apk backup is stored.
+ */
+ public final File backupDir;
+
+ /**
+ * The time when the upgrade occurred, for purposes of expiring
+ * rollback data.
+ */
+ public final Instant timestamp;
+
+ PackageRollbackData(PackageRollbackInfo info,
+ File backupDir, Instant timestamp) {
+ this.info = info;
+ this.backupDir = backupDir;
+ this.timestamp = timestamp;
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
new file mode 100644
index 000000000000..8c3f04f3b8a8
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.content.Context;
+import android.os.SELinux;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * Service that manages APK level rollbacks. Publishes
+ * Context.ROLLBACK_SERVICE.
+ *
+ * @hide
+ */
+public final class RollbackManagerService extends SystemService {
+
+ private static final String TAG = "RollbackManager";
+
+ private RollbackManagerServiceImpl mService;
+
+ public RollbackManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new RollbackManagerServiceImpl(getContext());
+
+ // TODO: Set up sepolicy to allow publishing the service.
+ if (SELinux.isSELinuxEnforced()) {
+ Log.w(TAG, "RollbackManager disabled pending selinux policy updates");
+ } else {
+ publishBinderService(Context.ROLLBACK_SERVICE, mService);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
new file mode 100644
index 000000000000..0c2131203808
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageParser;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
+import android.content.rollback.IRollbackManager;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import libcore.io.IoUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementation of service that manages APK level rollbacks.
+ */
+class RollbackManagerServiceImpl extends IRollbackManager.Stub {
+
+ private static final String TAG = "RollbackManager";
+
+ // Rollbacks expire after 48 hours.
+ // TODO: How to test rollback expiration works properly?
+ private static final long ROLLBACK_LIFETIME_DURATION_MILLIS = 48 * 60 * 60 * 1000;
+
+ // Lock used to synchronize accesses to in-memory rollback data
+ // structures. By convention, methods with the suffix "Locked" require
+ // mLock is held when they are called.
+ private final Object mLock = new Object();
+
+ // Package rollback data available to be used for rolling back a package.
+ // This list is null until the rollback data has been loaded.
+ @GuardedBy("mLock")
+ private List<PackageRollbackData> mAvailableRollbacks;
+
+ // The list of recently executed rollbacks.
+ // This list is null until the rollback data has been loaded.
+ @GuardedBy("mLock")
+ private List<RollbackInfo> mRecentlyExecutedRollbacks;
+
+ // Data for available rollbacks and recently executed rollbacks is
+ // persisted in storage. Assuming the rollback data directory is
+ // /data/rollback, we use the following directory structure
+ // to store this data:
+ // /data/rollback/
+ // available/
+ // com.package.A-XXX/
+ // base.apk
+ // rollback.json
+ // com.package.B-YYY/
+ // base.apk
+ // rollback.json
+ // recently_executed.json
+ // TODO: Use AtomicFile for rollback.json and recently_executed.json.
+ private final File mRollbackDataDir;
+ private final File mAvailableRollbacksDir;
+ private final File mRecentlyExecutedRollbacksFile;
+
+ private final Context mContext;
+ private final HandlerThread mHandlerThread;
+
+ RollbackManagerServiceImpl(Context context) {
+ mContext = context;
+ mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+ mHandlerThread.start();
+
+ mRollbackDataDir = new File(Environment.getDataDirectory(), "rollback");
+ mAvailableRollbacksDir = new File(mRollbackDataDir, "available");
+ mRecentlyExecutedRollbacksFile = new File(mRollbackDataDir, "recently_executed.json");
+
+ // Kick off loading of the rollback data from strorage in a background
+ // thread.
+ // TODO: Consider loading the rollback data directly here instead, to
+ // avoid the need to call ensureRollbackDataLoaded every time before
+ // accessing the rollback data?
+ // TODO: Test that this kicks off initial scheduling of rollback
+ // expiration.
+ getHandler().post(() -> ensureRollbackDataLoaded());
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+ String packageName = intent.getData().getSchemeSpecificPart();
+ onPackageReplaced(packageName);
+ }
+ if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+ String packageName = intent.getData().getSchemeSpecificPart();
+ onPackageFullyRemoved(packageName);
+ }
+ }
+ }, filter, null, getHandler());
+
+ IntentFilter enableRollbackFilter = new IntentFilter();
+ enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+ try {
+ enableRollbackFilter.addDataType("application/vnd.android.package-archive");
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.e(TAG, "addDataType", e);
+ }
+
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) {
+ int token = intent.getIntExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+ int installFlags = intent.getIntExtra(
+ PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
+ File newPackageCodePath = new File(intent.getData().getPath());
+
+ getHandler().post(() -> {
+ boolean success = enableRollback(installFlags, newPackageCodePath);
+ int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
+ if (!success) {
+ ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
+ }
+
+ PackageManagerInternal pm = LocalServices.getService(
+ PackageManagerInternal.class);
+ pm.setEnableRollbackCode(token, ret);
+ });
+
+ // We're handling the ordered broadcast. Abort the
+ // broadcast because there is no need for it to go to
+ // anyone else.
+ abortBroadcast();
+ }
+ }
+ }, enableRollbackFilter, null, getHandler());
+ }
+
+ @Override
+ public RollbackInfo getAvailableRollback(String packageName) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "getAvailableRollback");
+
+ PackageRollbackInfo.PackageVersion installedVersion =
+ getInstalledPackageVersion(packageName);
+ if (installedVersion == null) {
+ return null;
+ }
+
+ synchronized (mLock) {
+ // TODO: Have ensureRollbackDataLoadedLocked return the list of
+ // available rollbacks, to hopefully avoid forgetting to call it?
+ ensureRollbackDataLoadedLocked();
+ for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+ PackageRollbackData data = mAvailableRollbacks.get(i);
+ if (data.info.packageName.equals(packageName)
+ && data.info.higherVersion.equals(installedVersion)) {
+ // TODO: For atomic installs, check all dependent packages
+ // for available rollbacks and include that info here.
+ return new RollbackInfo(data.info);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public StringParceledListSlice getPackagesWithAvailableRollbacks() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "getPackagesWithAvailableRollbacks");
+
+ // TODO: This may return packages whose rollback is out of date or
+ // expired. Presumably that's okay because the package rollback could
+ // be expired anyway between when the caller calls this method and
+ // when the caller calls getAvailableRollback for more details.
+ final Set<String> packageNames = new HashSet<>();
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+ PackageRollbackData data = mAvailableRollbacks.get(i);
+ packageNames.add(data.info.packageName);
+ }
+ }
+ return new StringParceledListSlice(new ArrayList<>(packageNames));
+ }
+
+ @Override
+ public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "getRecentlyExecutedRollbacks");
+
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ List<RollbackInfo> rollbacks = new ArrayList<>(mRecentlyExecutedRollbacks);
+ return new ParceledListSlice<>(rollbacks);
+ }
+ }
+
+ @Override
+ public void executeRollback(RollbackInfo rollback, String callerPackageName,
+ IntentSender statusReceiver) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "executeRollback");
+
+ final int callingUid = Binder.getCallingUid();
+ AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ appOps.checkPackage(callingUid, callerPackageName);
+
+ getHandler().post(() ->
+ executeRollbackInternal(rollback, callerPackageName, statusReceiver));
+ }
+
+ /**
+ * Performs the actual work to execute a rollback.
+ * The work is done on the current thread. This may be a long running
+ * operation.
+ */
+ private void executeRollbackInternal(RollbackInfo rollback,
+ String callerPackageName, IntentSender statusReceiver) {
+ String packageName = rollback.targetPackage.packageName;
+ Log.i(TAG, "Initiating rollback of " + packageName);
+
+ PackageRollbackInfo.PackageVersion installedVersion =
+ getInstalledPackageVersion(packageName);
+ if (installedVersion == null) {
+ // TODO: Test this case
+ sendFailure(statusReceiver, "Target package to roll back is not installed");
+ return;
+ }
+
+ if (!rollback.targetPackage.higherVersion.equals(installedVersion)) {
+ // TODO: Test this case
+ sendFailure(statusReceiver, "Target package version to roll back not installed.");
+ return;
+ }
+
+ // TODO: We assume that between now and the time we commit the
+ // downgrade install, the currently installed package version does not
+ // change. This is not safe to assume, particularly in the case of a
+ // rollback racing with a roll-forward fix of a buggy package.
+ // Figure out how to ensure we don't commit the rollback if
+ // roll forward happens at the same time.
+ PackageRollbackData data = null;
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+ PackageRollbackData available = mAvailableRollbacks.get(i);
+ // TODO: Check if available.info.lowerVersion matches
+ // rollback.targetPackage.lowerVersion?
+ if (available.info.packageName.equals(packageName)
+ && available.info.higherVersion.equals(installedVersion)) {
+ data = available;
+ break;
+ }
+ }
+ }
+
+ if (data == null) {
+ sendFailure(statusReceiver, "Rollback not available");
+ return;
+ }
+
+ // Get a context for the caller to use to install the downgraded
+ // version of the package.
+ Context context = null;
+ try {
+ context = mContext.createPackageContext(callerPackageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ sendFailure(statusReceiver, "Invalid callerPackageName");
+ return;
+ }
+
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInstaller.Session session = null;
+
+ PackageInstaller packageInstaller = pm.getPackageInstaller();
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ params.setAllowDowngrade(true);
+ int sessionId = packageInstaller.createSession(params);
+ session = packageInstaller.openSession(sessionId);
+
+ // TODO: Will it always be called "base.apk"? What about splits?
+ File baseApk = new File(data.backupDir, "base.apk");
+ try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
+ ParcelFileDescriptor.MODE_READ_ONLY)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ session.write("base.apk", 0, baseApk.length(), fd);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ session.commit(receiver.getIntentSender());
+
+ Intent result = receiver.getResult();
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status != PackageInstaller.STATUS_SUCCESS) {
+ sendFailure(statusReceiver, "Rollback downgrade install failed: "
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
+ return;
+ }
+
+ addRecentlyExecutedRollback(rollback);
+ sendSuccess(statusReceiver);
+
+ Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
+ Uri.fromParts("package", packageName, Manifest.permission.MANAGE_ROLLBACKS));
+
+ // TODO: This call emits the warning "Calling a method in the
+ // system process without a qualified user". Fix that.
+ mContext.sendBroadcast(broadcast);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to roll back " + packageName, e);
+ sendFailure(statusReceiver, "IOException: " + e.toString());
+ return;
+ }
+ }
+
+ @Override
+ public void reloadPersistedData() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "reloadPersistedData");
+
+ synchronized (mLock) {
+ mAvailableRollbacks = null;
+ mRecentlyExecutedRollbacks = null;
+ }
+ getHandler().post(() -> ensureRollbackDataLoaded());
+ }
+
+ @Override
+ public void expireRollbackForPackage(String packageName) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ "expireRollbackForPackage");
+
+ // TODO: Should this take a package version number in addition to
+ // package name? For now, just remove all rollbacks matching the
+ // package name. This method is only currently used to facilitate
+ // testing anyway.
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+ while (iter.hasNext()) {
+ PackageRollbackData data = iter.next();
+ if (data.info.packageName.equals(packageName)) {
+ iter.remove();
+ removeFile(data.backupDir);
+ }
+ }
+ }
+ }
+
+ /**
+ * Load rollback data from storage if it has not already been loaded.
+ * After calling this funciton, mAvailableRollbacks and
+ * mRecentlyExecutedRollbacks will be non-null.
+ */
+ private void ensureRollbackDataLoaded() {
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ }
+ }
+
+ /**
+ * Load rollback data from storage if it has not already been loaded.
+ * After calling this function, mAvailableRollbacks and
+ * mRecentlyExecutedRollbacks will be non-null.
+ */
+ @GuardedBy("mLock")
+ private void ensureRollbackDataLoadedLocked() {
+ if (mAvailableRollbacks == null) {
+ loadRollbackDataLocked();
+ }
+ }
+
+ /**
+ * Load rollback data from storage.
+ * Note: We do potentially heavy IO here while holding mLock, because we
+ * have to have the rollback data loaded before we can do anything else
+ * meaningful.
+ */
+ @GuardedBy("mLock")
+ private void loadRollbackDataLocked() {
+ mAvailableRollbacksDir.mkdirs();
+ mAvailableRollbacks = new ArrayList<>();
+ for (File rollbackDir : mAvailableRollbacksDir.listFiles()) {
+ if (rollbackDir.isDirectory()) {
+ // TODO: How to detect and clean up an invalid rollback
+ // directory? We don't know if it's invalid because something
+ // went wrong, or if it's only temporarily invalid because
+ // it's in the process of being created.
+ try {
+ File jsonFile = new File(rollbackDir, "rollback.json");
+ String jsonString = IoUtils.readFileAsString(jsonFile.getAbsolutePath());
+ JSONObject jsonObject = new JSONObject(jsonString);
+ String packageName = jsonObject.getString("packageName");
+ long higherVersionCode = jsonObject.getLong("higherVersionCode");
+ long lowerVersionCode = jsonObject.getLong("lowerVersionCode");
+ Instant timestamp = Instant.parse(jsonObject.getString("timestamp"));
+ PackageRollbackData data = new PackageRollbackData(
+ new PackageRollbackInfo(packageName,
+ new PackageRollbackInfo.PackageVersion(higherVersionCode),
+ new PackageRollbackInfo.PackageVersion(lowerVersionCode)),
+ rollbackDir, timestamp);
+ mAvailableRollbacks.add(data);
+ } catch (IOException | JSONException | DateTimeParseException e) {
+ Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+ }
+ }
+ }
+
+ mRecentlyExecutedRollbacks = new ArrayList<>();
+ if (mRecentlyExecutedRollbacksFile.exists()) {
+ try {
+ // TODO: How to cope with changes to the format of this file from
+ // when RollbackStore is updated in the future?
+ String jsonString = IoUtils.readFileAsString(
+ mRecentlyExecutedRollbacksFile.getAbsolutePath());
+ JSONObject object = new JSONObject(jsonString);
+ JSONArray array = object.getJSONArray("recentlyExecuted");
+ for (int i = 0; i < array.length(); ++i) {
+ JSONObject element = array.getJSONObject(i);
+ String packageName = element.getString("packageName");
+ long higherVersionCode = element.getLong("higherVersionCode");
+ long lowerVersionCode = element.getLong("lowerVersionCode");
+ PackageRollbackInfo target = new PackageRollbackInfo(packageName,
+ new PackageRollbackInfo.PackageVersion(higherVersionCode),
+ new PackageRollbackInfo.PackageVersion(lowerVersionCode));
+ RollbackInfo rollback = new RollbackInfo(target);
+ mRecentlyExecutedRollbacks.add(rollback);
+ }
+ } catch (IOException | JSONException e) {
+ // TODO: What to do here? Surely we shouldn't just forget about
+ // everything after the point of exception?
+ Log.e(TAG, "Failed to read recently executed rollbacks", e);
+ }
+ }
+
+ scheduleExpiration(0);
+ }
+
+ /**
+ * Called when a package has been replaced with a different version.
+ * Removes all backups for the package not matching the currently
+ * installed package version.
+ */
+ private void onPackageReplaced(String packageName) {
+ // TODO: Could this end up incorrectly deleting a rollback for a
+ // package that is about to be installed?
+ PackageRollbackInfo.PackageVersion installedVersion =
+ getInstalledPackageVersion(packageName);
+
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+ while (iter.hasNext()) {
+ PackageRollbackData data = iter.next();
+ if (data.info.packageName.equals(packageName)
+ && !data.info.higherVersion.equals(installedVersion)) {
+ iter.remove();
+ removeFile(data.backupDir);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called when a package has been completely removed from the device.
+ * Removes all backups and rollback history for the given package.
+ */
+ private void onPackageFullyRemoved(String packageName) {
+ expireRollbackForPackage(packageName);
+
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ Iterator<RollbackInfo> iter = mRecentlyExecutedRollbacks.iterator();
+ boolean changed = false;
+ while (iter.hasNext()) {
+ RollbackInfo rollback = iter.next();
+ if (packageName.equals(rollback.targetPackage.packageName)) {
+ iter.remove();
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ saveRecentlyExecutedRollbacksLocked();
+ }
+ }
+ }
+
+ /**
+ * Write the list of recently executed rollbacks to storage.
+ * Note: This happens while mLock is held, which should be okay because we
+ * expect executed rollbacks to be modified only in exceptional cases.
+ */
+ @GuardedBy("mLock")
+ private void saveRecentlyExecutedRollbacksLocked() {
+ try {
+ JSONObject json = new JSONObject();
+ JSONArray array = new JSONArray();
+ json.put("recentlyExecuted", array);
+
+ for (int i = 0; i < mRecentlyExecutedRollbacks.size(); ++i) {
+ RollbackInfo rollback = mRecentlyExecutedRollbacks.get(i);
+ JSONObject element = new JSONObject();
+ element.put("packageName", rollback.targetPackage.packageName);
+ element.put("higherVersionCode", rollback.targetPackage.higherVersion.versionCode);
+ element.put("lowerVersionCode", rollback.targetPackage.lowerVersion.versionCode);
+ array.put(element);
+ }
+
+ PrintWriter pw = new PrintWriter(mRecentlyExecutedRollbacksFile);
+ pw.println(json.toString());
+ pw.close();
+ } catch (IOException | JSONException e) {
+ // TODO: What to do here?
+ Log.e(TAG, "Failed to save recently executed rollbacks", e);
+ }
+ }
+
+ /**
+ * Records that the given package has been recently rolled back.
+ */
+ private void addRecentlyExecutedRollback(RollbackInfo rollback) {
+ // TODO: if the list of rollbacks gets too big, trim it to only those
+ // that are necessary to keep track of.
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ mRecentlyExecutedRollbacks.add(rollback);
+ saveRecentlyExecutedRollbacksLocked();
+ }
+ }
+
+ /**
+ * Notifies an IntentSender of failure.
+ *
+ * @param statusReceiver where to send the failure
+ * @param message the failure message.
+ */
+ private void sendFailure(IntentSender statusReceiver, String message) {
+ Log.e(TAG, message);
+ try {
+ // TODO: More context on which rollback failed?
+ // TODO: More refined failure code?
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
+ statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ // Nowhere to send the result back to, so don't bother.
+ }
+ }
+
+ /**
+ * Notifies an IntentSender of success.
+ */
+ private void sendSuccess(IntentSender statusReceiver) {
+ try {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_SUCCESS);
+ statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ // Nowhere to send the result back to, so don't bother.
+ }
+ }
+
+ // Check to see if anything needs expiration, and if so, expire it.
+ // Schedules future expiration as appropriate.
+ // TODO: Handle cases where the user changes time on the device.
+ private void runExpiration() {
+ Instant now = Instant.now();
+ Instant oldest = null;
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+
+ Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
+ while (iter.hasNext()) {
+ PackageRollbackData data = iter.next();
+ if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
+ iter.remove();
+ removeFile(data.backupDir);
+ } else if (oldest == null || oldest.isAfter(data.timestamp)) {
+ oldest = data.timestamp;
+ }
+ }
+ }
+
+ if (oldest != null) {
+ scheduleExpiration(now.until(oldest.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS),
+ ChronoUnit.MILLIS));
+ }
+ }
+
+ /**
+ * Schedules an expiration check to be run after the given duration in
+ * milliseconds has gone by.
+ */
+ private void scheduleExpiration(long duration) {
+ getHandler().postDelayed(() -> runExpiration(), duration);
+ }
+
+ private Handler getHandler() {
+ return mHandlerThread.getThreadHandler();
+ }
+
+ /**
+ * Called via broadcast by the package manager when a package is being
+ * staged for install with rollback enabled. Called before the package has
+ * been installed.
+ *
+ * @param id the id of the enable rollback request
+ * @param installFlags information about what is being installed.
+ * @param newPackageCodePath path to the package about to be installed.
+ * @return true if enabling the rollback succeeds, false otherwise.
+ */
+ private boolean enableRollback(int installFlags, File newPackageCodePath) {
+ if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+ Log.e(TAG, "Rollbacks not supported for instant app install");
+ return false;
+ }
+ if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+ Log.e(TAG, "Rollbacks not supported for apex install");
+ return false;
+ }
+
+ // Get information about the package to be installed.
+ PackageParser.PackageLite newPackage = null;
+ try {
+ newPackage = PackageParser.parsePackageLite(newPackageCodePath, 0);
+ } catch (PackageParser.PackageParserException e) {
+ Log.e(TAG, "Unable to parse new package", e);
+ return false;
+ }
+
+ String packageName = newPackage.packageName;
+ Log.i(TAG, "Enabling rollback for install of " + packageName);
+
+ PackageRollbackInfo.PackageVersion newVersion =
+ new PackageRollbackInfo.PackageVersion(newPackage.versionCode);
+
+ // Get information about the currently installed package.
+ PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+ PackageParser.Package installedPackage = pm.getPackage(packageName);
+ if (installedPackage == null) {
+ // TODO: Support rolling back fresh package installs rather than
+ // fail here. Test this case.
+ Log.e(TAG, packageName + " is not installed");
+ return false;
+ }
+ PackageRollbackInfo.PackageVersion installedVersion =
+ new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode());
+
+ File backupDir;
+ try {
+ backupDir = Files.createTempDirectory(
+ mAvailableRollbacksDir.toPath(), packageName + "-").toFile();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to create rollback for " + packageName, e);
+ return false;
+ }
+
+ // TODO: Should the timestamp be for when we commit the install, not
+ // when we create the pending one?
+ Instant timestamp = Instant.now();
+ try {
+ JSONObject json = new JSONObject();
+ json.put("packageName", packageName);
+ json.put("higherVersionCode", newVersion.versionCode);
+ json.put("lowerVersionCode", installedVersion.versionCode);
+ json.put("timestamp", timestamp.toString());
+
+ File jsonFile = new File(backupDir, "rollback.json");
+ PrintWriter pw = new PrintWriter(jsonFile);
+ pw.println(json.toString());
+ pw.close();
+ } catch (IOException | JSONException e) {
+ Log.e(TAG, "Unable to create rollback for " + packageName, e);
+ removeFile(backupDir);
+ return false;
+ }
+
+ // TODO: Copy by hard link instead to save on cpu and storage space?
+ int status = PackageManagerServiceUtils.copyPackage(installedPackage.codePath, backupDir);
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ Log.e(TAG, "Unable to copy package for rollback for " + packageName);
+ removeFile(backupDir);
+ return false;
+ }
+
+ PackageRollbackData data = new PackageRollbackData(
+ new PackageRollbackInfo(packageName, newVersion, installedVersion),
+ backupDir, timestamp);
+
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ mAvailableRollbacks.add(data);
+ }
+
+ return true;
+ }
+
+ // TODO: Don't copy this from PackageManagerShellCommand like this?
+ private static class LocalIntentReceiver {
+ private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
+
+ private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+ try {
+ mResult.offer(intent, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public Intent getResult() {
+ try {
+ return mResult.take();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Deletes a file completely.
+ * If the file is a directory, its contents are deleted as well.
+ * Has no effect if the directory does not exist.
+ */
+ private void removeFile(File file) {
+ if (file.isDirectory()) {
+ for (File child : file.listFiles()) {
+ removeFile(child);
+ }
+ }
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ /**
+ * Gets the version of the package currently installed.
+ * Returns null if the package is not currently installed.
+ */
+ private PackageRollbackInfo.PackageVersion getInstalledPackageVersion(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ PackageInfo pkgInfo = null;
+ try {
+ pkgInfo = pm.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+
+ return new PackageRollbackInfo.PackageVersion(pkgInfo.getLongVersionCode());
+ }
+}
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 667d21dc59a0..839ed302ba73 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -30,6 +30,7 @@ import android.util.apk.VerityBuilder;
import libcore.util.HexEncoding;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -49,11 +50,27 @@ import sun.security.pkcs.PKCS7;
abstract public class VerityUtils {
private static final String TAG = "VerityUtils";
+ /**
+ * File extension of the signature file. For example, foo.apk.fsv_sig is the signature file of
+ * foo.apk.
+ */
+ public static final String FSVERITY_SIGNATURE_FILE_EXTENSION = ".fsv_sig";
+
/** The maximum size of signature file. This is just to avoid potential abuse. */
private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
private static final boolean DEBUG = false;
+ /** Returns true if the given file looks like containing an fs-verity signature. */
+ public static boolean isFsveritySignatureFile(File file) {
+ return file.getName().endsWith(FSVERITY_SIGNATURE_FILE_EXTENSION);
+ }
+
+ /** Returns the fs-verity signature file path of the given file. */
+ public static String getFsveritySignatureFilePath(String filePath) {
+ return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION;
+ }
+
/** Returns whether the file has fs-verity enabled. */
public static boolean hasFsverity(@NonNull String filePath) {
// NB: only measure but not check the actual measurement here. As long as this succeeds,
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
index 4908964109ad..438c303de6cc 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
+++ b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
@@ -30,7 +30,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.Set;
-class SignedConfigApplicator {
+class GlobalSettingsConfigApplicator {
private static final String TAG = "SignedConfig";
@@ -68,7 +68,7 @@ class SignedConfigApplicator {
private final String mSourcePackage;
private final SignatureVerifier mVerifier;
- SignedConfigApplicator(Context context, String sourcePackage) {
+ GlobalSettingsConfigApplicator(Context context, String sourcePackage) {
mContext = context;
mSourcePackage = sourcePackage;
mVerifier = new SignatureVerifier();
@@ -102,7 +102,7 @@ class SignedConfigApplicator {
void applyConfig(String configStr, String signature) {
if (!checkSignature(configStr, signature)) {
- Slog.e(TAG, "Signature check on signed configuration in package " + mSourcePackage
+ Slog.e(TAG, "Signature check on global settings in package " + mSourcePackage
+ " failed; ignoring");
return;
}
@@ -110,26 +110,26 @@ class SignedConfigApplicator {
try {
config = SignedConfig.parse(configStr, ALLOWED_KEYS, KEY_VALUE_MAPPERS);
} catch (InvalidConfigException e) {
- Slog.e(TAG, "Failed to parse config from package " + mSourcePackage, e);
+ Slog.e(TAG, "Failed to parse global settings from package " + mSourcePackage, e);
return;
}
int currentVersion = getCurrentConfigVersion();
if (currentVersion >= config.version) {
- Slog.i(TAG, "Config from package " + mSourcePackage + " is older than existing: "
- + config.version + "<=" + currentVersion);
+ Slog.i(TAG, "Global settings from package " + mSourcePackage
+ + " is older than existing: " + config.version + "<=" + currentVersion);
return;
}
// We have new config!
- Slog.i(TAG, "Got new signed config from package " + mSourcePackage + ": version "
+ Slog.i(TAG, "Got new global settings from package " + mSourcePackage + ": version "
+ config.version + " replacing existing version " + currentVersion);
SignedConfig.PerSdkConfig matchedConfig =
config.getMatchingConfig(Build.VERSION.SDK_INT);
if (matchedConfig == null) {
- Slog.i(TAG, "Config is not applicable to current SDK version; ignoring");
+ Slog.i(TAG, "Settings is not applicable to current SDK version; ignoring");
return;
}
- Slog.i(TAG, "Updating signed config to version " + config.version);
+ Slog.i(TAG, "Updating global settings to version " + config.version);
updateCurrentConfig(config.version, matchedConfig.values);
}
}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
index 84ce93f04c74..6bcee1413fa8 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -42,8 +42,8 @@ public class SignedConfigService {
private static final String TAG = "SignedConfig";
// TODO should these be elsewhere? In a public API?
- private static final String KEY_CONFIG = "android.signedconfig";
- private static final String KEY_CONFIG_SIGNATURE = "android.signedconfig.signature";
+ private static final String KEY_GLOBAL_SETTINGS = "android.settings.global";
+ private static final String KEY_GLOBAL_SETTINGS_SIGNATURE = "android.settings.global.signature";
private static class UpdateReceiver extends BroadcastReceiver {
@Override
@@ -80,25 +80,25 @@ public class SignedConfigService {
if (DBG) Slog.d(TAG, "handlePackageBroadcast: no metadata");
return;
}
- if (metaData.containsKey(KEY_CONFIG)
- && metaData.containsKey(KEY_CONFIG_SIGNATURE)) {
- String config = metaData.getString(KEY_CONFIG);
- String signature = metaData.getString(KEY_CONFIG_SIGNATURE);
+ if (metaData.containsKey(KEY_GLOBAL_SETTINGS)
+ && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) {
+ String config = metaData.getString(KEY_GLOBAL_SETTINGS);
+ String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
try {
// Base64 encoding is standard (not URL safe) encoding: RFC4648
config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
} catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to base64 decode config from " + packageName);
+ Slog.e(TAG, "Failed to base64 decode global settings config from " + packageName);
return;
}
if (DBG) {
- Slog.d(TAG, "Got signed config: " + config);
- Slog.d(TAG, "Got config signature: " + signature);
+ Slog.d(TAG, "Got global settings config: " + config);
+ Slog.d(TAG, "Got global settings signature: " + signature);
}
- new SignedConfigApplicator(mContext, packageName).applyConfig(
+ new GlobalSettingsConfigApplicator(mContext, packageName).applyConfig(
config, signature);
} else {
- if (DBG) Slog.d(TAG, "Package has no config/signature.");
+ if (DBG) Slog.d(TAG, "Package has no global settings config/signature.");
}
}
diff --git a/services/core/java/com/android/server/slice/SliceClientPermissions.java b/services/core/java/com/android/server/slice/SliceClientPermissions.java
index e461e0d43735..ab94a59c4d9c 100644
--- a/services/core/java/com/android/server/slice/SliceClientPermissions.java
+++ b/services/core/java/com/android/server/slice/SliceClientPermissions.java
@@ -282,9 +282,12 @@ public class SliceClientPermissions implements DirtyTracker, Persistable {
public synchronized void writeTo(XmlSerializer out) throws IOException {
final int N = mPaths.size();
for (int i = 0; i < N; i++) {
- out.startTag(NAMESPACE, TAG_PATH);
- out.text(encodeSegments(mPaths.valueAt(i)));
- out.endTag(NAMESPACE, TAG_PATH);
+ final String[] segments = mPaths.valueAt(i);
+ if (segments != null) {
+ out.startTag(NAMESPACE, TAG_PATH);
+ out.text(encodeSegments(segments));
+ out.endTag(NAMESPACE, TAG_PATH);
+ }
}
}
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 780bc962afba..315d5e39c94b 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -315,7 +315,8 @@ public class SlicePermissionManager implements DirtyTracker {
return new AtomicFile(new File(mSliceDir, fileName));
}
- private void handlePersist() {
+ @VisibleForTesting
+ void handlePersist() {
synchronized (this) {
for (Persistable persistable : mDirty) {
AtomicFile file = getFile(persistable.getFileName());
@@ -335,7 +336,7 @@ public class SlicePermissionManager implements DirtyTracker {
out.flush();
file.finishWrite(stream);
- } catch (IOException | XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException | RuntimeException e) {
Slog.w(TAG, "Failed to save access file, restoring backup", e);
file.failWrite(stream);
}
@@ -344,6 +345,12 @@ public class SlicePermissionManager implements DirtyTracker {
}
}
+ // use addPersistableDirty(); this is just for tests
+ @VisibleForTesting
+ void addDirtyImmediate(Persistable obj) {
+ mDirty.add(obj);
+ }
+
private void handleRemove(PkgUser pkgUser) {
getFile(SliceClientPermissions.getFileName(pkgUser)).delete();
getFile(SliceProviderPermissions.getFileName(pkgUser)).delete();
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 973499f098b2..1f638c7f2e5d 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -37,6 +37,7 @@ import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER
import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
import static com.android.server.am.ActivityDisplayProto.ID;
import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
+import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
@@ -120,6 +121,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
*/
private boolean mRemoved;
+ /** The display can only contain one task. */
+ private boolean mSingleTaskInstance;
+
/**
* A focusable stack that is purposely to be positioned at the top. Although the stack may not
* have the topmost index, it is used as a preferred candidate to prevent being unable to resume
@@ -244,6 +248,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
? getFocusedStack() : null;
final boolean wasContained = mStacks.remove(stack);
+ if (mSingleTaskInstance && getChildCount() > 0) {
+ throw new IllegalStateException(
+ "positionChildAt: Can only have one child on display=" + this);
+ }
final int insertPosition = getTopInsertPosition(stack, position);
mStacks.add(insertPosition, stack);
@@ -403,6 +411,14 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
*/
<T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
+ if (mSingleTaskInstance && getChildCount() > 0) {
+ // Create stack on default display instead since this display can only contain 1 stack.
+ // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
+ // this goes away once ActivityView is no longer using virtual displays.
+ return mRootActivityContainer.getDefaultDisplay().createStack(
+ windowingMode, activityType, onTop);
+ }
+
if (activityType == ACTIVITY_TYPE_UNDEFINED) {
// Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
// anything else should be passing it in anyways...
@@ -1337,8 +1353,31 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
}
}
+ void setDisplayToSingleTaskInstance() {
+ final int childCount = getChildCount();
+ if (childCount > 1) {
+ throw new IllegalArgumentException("Display already has multiple stacks. display="
+ + this);
+ }
+ if (childCount > 0) {
+ final ActivityStack stack = getChildAt(0);
+ if (stack.getChildCount() > 1) {
+ throw new IllegalArgumentException("Display stack already has multiple tasks."
+ + " display=" + this + " stack=" + stack);
+ }
+ }
+
+ mSingleTaskInstance = true;
+ }
+
+ /** Returns true if the display can only contain one task */
+ boolean isSingleTaskInstance() {
+ return mSingleTaskInstance;
+ }
+
public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
+ pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
+ + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
final String myPrefix = prefix + " ";
if (mHomeStack != null) {
pw.println(myPrefix + "mHomeStack=" + mHomeStack);
@@ -1373,6 +1412,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
proto.write(ID, mDisplayId);
+ proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
final ActivityStack focusedStack = getFocusedStack();
if (focusedStack != null) {
proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2cd0168aff42..8884615d2fe1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -271,7 +271,10 @@ final class ActivityRecord extends ConfigurationContainer {
boolean fullscreen; // The activity is opaque and fills the entire space of this task.
// TODO: See if it possible to combine this with the fullscreen field.
final boolean hasWallpaper; // Has a wallpaper window as a background.
- final boolean noDisplay; // activity is not displayed?
+ @VisibleForTesting
+ boolean noDisplay; // activity is not displayed?
+ @VisibleForTesting
+ int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity.
private final boolean componentSpecified; // did caller specify an explicit component?
final boolean rootVoiceInteraction; // was this the root activity of a voice interaction?
@@ -1019,6 +1022,8 @@ final class ActivityRecord extends ConfigurationContainer {
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
}
+ // Gets launch display id from options. It returns INVALID_DISPLAY if not set.
+ mHandoverLaunchDisplayId = options.getLaunchDisplayId();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6755c7363ede..4581a0f9f350 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -66,6 +66,8 @@ import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
+import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
@@ -309,7 +311,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
*/
- final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
+ private final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
/**
* When we are in the process of pausing an activity, before starting the
@@ -1142,6 +1144,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
}
+ /** @return true if the stack can only contain one task */
+ boolean isSingleTaskInstance() {
+ final ActivityDisplay display = getDisplay();
+ return display != null && display.isSingleTaskInstance();
+ }
+
final void removeActivitiesFromLRUListLocked(TaskRecord task) {
for (ActivityRecord r : task.mActivities) {
mLRUActivities.remove(r);
@@ -5153,6 +5161,47 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
}
+ boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
+ String dumpPackage, boolean needSep) {
+ pw.println(" Stack #" + mStackId
+ + ": type=" + activityTypeToString(getActivityType())
+ + " mode=" + windowingModeToString(getWindowingMode()));
+ pw.println(" isSleeping=" + shouldSleepActivities());
+ pw.println(" mBounds=" + getRequestedOverrideBounds());
+
+ boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
+ needSep);
+
+ printed |= dumpHistoryList(fd, pw, mLRUActivities, " ", "Run", false,
+ !dumpAll, false, dumpPackage, true,
+ " Running activities (most recent first):", null);
+
+ needSep = printed;
+ boolean pr = printThisActivity(pw, mPausingActivity, dumpPackage, needSep,
+ " mPausingActivity: ");
+ if (pr) {
+ printed = true;
+ needSep = false;
+ }
+ pr = printThisActivity(pw, getResumedActivity(), dumpPackage, needSep,
+ " mResumedActivity: ");
+ if (pr) {
+ printed = true;
+ needSep = false;
+ }
+ if (dumpAll) {
+ pr = printThisActivity(pw, mLastPausedActivity, dumpPackage, needSep,
+ " mLastPausedActivity: ");
+ if (pr) {
+ printed = true;
+ needSep = true;
+ }
+ printed |= printThisActivity(pw, mLastNoHistoryActivity, dumpPackage,
+ needSep, " mLastNoHistoryActivity: ");
+ }
+ return printed;
+ }
+
boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, boolean needSep) {
@@ -5172,7 +5221,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
pw.println(prefix + "* " + task);
task.dump(pw, prefix + " ");
- ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
+ dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
}
return true;
@@ -5241,11 +5290,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
*/
void removeTask(TaskRecord task, String reason, int mode) {
- // TODO(b/119259346): Move some logic below to TaskRecord. See bug for more context.
- for (ActivityRecord record : task.mActivities) {
- onActivityRemovedFromStack(record);
- }
-
final boolean removed = mTaskHistory.remove(task);
if (removed) {
@@ -5255,25 +5299,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
removeActivitiesFromLRUListLocked(task);
updateTaskMovement(task, true);
- if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
- // This task is going away, so save the last state if necessary.
- task.saveLaunchingStateIfNeeded();
-
- // TODO: VI what about activity?
- final boolean isVoiceSession = task.voiceSession != null;
- if (isVoiceSession) {
- try {
- task.voiceSession.taskFinished(task.intent, task.taskId);
- } catch (RemoteException e) {
- }
- }
- if (task.autoRemoveFromRecents() || isVoiceSession) {
- // Task creator asked to remove this when done, or this task was a voice
- // interaction, so it should not remain on the recent tasks list.
- mStackSupervisor.mRecentTasks.remove(task);
- }
-
- task.removeWindowContainer();
+ if (mode == REMOVE_TASK_MODE_DESTROYING) {
+ task.cleanUpResourcesForDestroy();
}
if (mTaskHistory.isEmpty()) {
@@ -5348,6 +5375,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
String reason) {
// TODO: Is this remove really needed? Need to look into the call path for the other addTask
mTaskHistory.remove(task);
+ if (isSingleTaskInstance() && !mTaskHistory.isEmpty()) {
+ throw new IllegalStateException("Can only have one child on stack=" + this);
+ }
+
position = getAdjustedPositionForTask(task, position, null /* starting */);
final boolean toTop = position >= mTaskHistory.size();
final ActivityStack prevStack = preAddTask(task, reason, toTop);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index f58b83d682f6..a50ae8431cb0 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -947,6 +947,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
+ boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
@@ -965,6 +966,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// If a dead object exception was thrown -- fall through to
// restart the application.
+ knownToBeDead = true;
}
// Suppress transition until the new activity becomes ready, otherwise the keyguard can
@@ -978,7 +980,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// ATMS lock held.
final Message msg = PooledLambda.obtainMessage(
ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
- r.info.applicationInfo, true, "activity", r.intent.getComponent());
+ r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
mService.mH.sendMessage(msg);
}
@@ -2657,7 +2659,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
return mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
- false /* validateIncomingUser */, null /* originatingPendingIntent */);
+ false /* validateIncomingUser */, null /* originatingPendingIntent */,
+ false /* allowBackgroundActivityStart */);
} finally {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
// If we are launching the task in the docked stack, put it into resizing mode so
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index b4d5d9f6e5cd..08596836ed4d 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -258,7 +258,7 @@ public class ActivityStartController {
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
reason);
@@ -278,6 +278,7 @@ public class ActivityStartController {
.setMayWait(userId)
.setInTask(inTask)
.setOriginatingPendingIntent(originatingPendingIntent)
+ .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
.execute();
}
@@ -294,7 +295,8 @@ public class ActivityStartController {
*/
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
- boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart) {
final String reason = "startActivityInPackage";
@@ -303,12 +305,13 @@ public class ActivityStartController {
// TODO: Switch to user app stacks here.
return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options,
- userId, reason, originatingPendingIntent);
+ userId, reason, originatingPendingIntent, allowBackgroundActivityStart);
}
int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
- int userId, String reason, PendingIntentRecord originatingPendingIntent) {
+ int userId, String reason, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
@@ -387,6 +390,7 @@ public class ActivityStartController {
// top one as otherwise an activity below might consume it.
.setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
.setOriginatingPendingIntent(originatingPendingIntent)
+ .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
.execute();
if (res < 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 36701ea599dc..b100ecdb0e73 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -323,6 +323,7 @@ class ActivityStarter {
WaitResult waitResult;
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
+ boolean allowBackgroundActivityStart;
/**
* If set to {@code true}, allows this activity start to look into
@@ -380,6 +381,7 @@ class ActivityStarter {
allowPendingRemoteAnimationRegistryLookup = true;
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
+ allowBackgroundActivityStart = false;
}
/**
@@ -419,6 +421,7 @@ class ActivityStarter {
= request.allowPendingRemoteAnimationRegistryLookup;
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
+ allowBackgroundActivityStart = request.allowBackgroundActivityStart;
}
}
@@ -504,7 +507,7 @@ class ActivityStarter {
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
- mRequest.originatingPendingIntent);
+ mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
} else {
return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
@@ -515,7 +518,7 @@ class ActivityStarter {
mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
mRequest.outActivity, mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
- mRequest.originatingPendingIntent);
+ mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
}
} finally {
onExecutionComplete();
@@ -548,7 +551,7 @@ class ActivityStarter {
SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
@@ -561,7 +564,8 @@ class ActivityStarter {
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
- inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
+ inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
+ allowBackgroundActivityStart);
if (outActivity != null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
@@ -592,7 +596,7 @@ class ActivityStarter {
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle
@@ -742,7 +746,7 @@ class ActivityStarter {
// on START_ABORTED
if (!abort) {
abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
- callerApp);
+ callerApp, originatingPendingIntent, allowBackgroundActivityStart);
}
// Merge the two options bundles, while realCallerOptions takes precedence.
@@ -890,7 +894,8 @@ class ActivityStarter {
}
private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
- int realCallingUid, WindowProcessController callerApp) {
+ int realCallingUid, WindowProcessController callerApp,
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
if (mService.isBackgroundActivityStartsEnabled()) {
return false;
}
@@ -902,12 +907,25 @@ class ActivityStarter {
if (callerApp != null && callerApp.hasForegroundActivities()) {
return false;
}
- // don't abort if the callingUid is in the foreground
- if (isUidForeground(callingUid)) {
+ // don't abort if the callingUid is in the foreground or is a persistent system process
+ if (isUidForeground(callingUid) || isUidPersistentSystemProcess(callingUid)) {
return false;
}
- // don't abort if the realCallingUid is in the foreground and callingUid isn't
- if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) {
+ // take realCallingUid into consideration
+ if (realCallingUid != callingUid) {
+ // don't abort if the realCallingUid is in the foreground and callingUid isn't
+ if (isUidForeground(realCallingUid)) {
+ return false;
+ }
+ // if the realCallingUid is a persistent system process, abort if the IntentSender
+ // wasn't whitelisted to start an activity
+ if (isUidPersistentSystemProcess(realCallingUid) && (originatingPendingIntent != null)
+ && allowBackgroundActivityStart) {
+ return false;
+ }
+ }
+ // don't abort if the caller is currently temporarily whitelisted
+ if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) {
return false;
}
// don't abort if the caller has the same uid as the recents component
@@ -924,12 +942,17 @@ class ActivityStarter {
return true;
}
- /** Returns true if uid has a visible window or its process is in top or persistent state. */
+ /** Returns true if uid has a visible window or its process is in a top state. */
private boolean isUidForeground(int uid) {
- return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_TOP)
+ return (mService.getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
|| mService.mWindowManager.isAnyWindowVisibleForUid(uid);
}
+ /** Returns true if uid is in a persistent state. */
+ private boolean isUidPersistentSystemProcess(int uid) {
+ return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+ }
+
private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
Intent intent, WindowProcessController callerApp, ActivityRecord r,
PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
@@ -1049,7 +1072,7 @@ class ActivityStarter {
Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
int userId, TaskRecord inTask, String reason,
boolean allowPendingRemoteAnimationRegistryLookup,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -1195,7 +1218,8 @@ class ActivityStarter {
voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
- allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
+ allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
+ allowBackgroundActivityStart);
Binder.restoreCallingIdentity(origId);
@@ -2731,6 +2755,11 @@ class ActivityStarter {
return this;
}
+ ActivityStarter setAllowBackgroundActivityStart(boolean allowBackgroundActivityStart) {
+ mRequest.allowBackgroundActivityStart = allowBackgroundActivityStart;
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0fc890a39fed..0f286ce30ccd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -197,16 +197,19 @@ public abstract class ActivityTaskManagerInternal {
* @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID.
* @param originatingPendingIntent PendingIntentRecord that originated this activity start or
* null if not originated by PendingIntent
+ * @param allowBackgroundActivityStart Whether the background activity start should be allowed
+ * from originatingPendingIntent
*/
public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
- boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent);
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart);
public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent);
+ PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart);
/**
* Start activity {@code intent} without calling user-id check.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c4be1ba53706..42121ca08696 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -639,7 +639,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- ActivityTaskManagerService(Context context) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public ActivityTaskManagerService(Context context) {
mContext = context;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
@@ -960,7 +961,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// TODO: Switch to user app stacks here.
return getActivityStartController().startActivities(caller, -1, callingPackage, intents,
resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason,
- null /* originatingPendingIntent */);
+ null /* originatingPendingIntent */, false /* allowBackgroundActivityStart */);
}
@Override
@@ -4569,6 +4570,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ /**
+ * Makes the display with the given id a single task instance display. I.e the display can only
+ * contain one task.
+ */
+ @Override
+ public void setDisplayToSingleTaskInstance(int displayId) {
+ mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "setDisplayToSingleTaskInstance");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ final ActivityDisplay display =
+ mRootActivityContainer.getActivityDisplayOrCreate(displayId);
+ if (display != null) {
+ display.setDisplayToSingleTaskInstance();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {
@@ -5787,18 +5808,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
packageUid, packageName,
intents, resolvedTypes, null /* resultTo */,
SafeActivityOptions.fromBundle(bOptions), userId,
- false /* validateIncomingUser */, null /* originatingPendingIntent */);
+ false /* validateIncomingUser */, null /* originatingPendingIntent */,
+ false /* allowBackgroundActivityStart */);
}
}
@Override
public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
- boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+ boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart) {
synchronized (mGlobalLock) {
return getActivityStartController().startActivitiesInPackage(uid, callingPackage,
intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
- originatingPendingIntent);
+ originatingPendingIntent, allowBackgroundActivityStart);
}
}
@@ -5807,12 +5830,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
- PendingIntentRecord originatingPendingIntent) {
+ PendingIntentRecord originatingPendingIntent,
+ boolean allowBackgroundActivityStart) {
synchronized (mGlobalLock) {
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
requestCode, startFlags, options, userId, inTask, reason,
- validateIncomingUser, originatingPendingIntent);
+ validateIncomingUser, originatingPendingIntent,
+ allowBackgroundActivityStart);
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index d8b2b5200f0c..a5341ca11784 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1949,6 +1949,11 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
} else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
+ if (mWmService.mLowRamTaskSnapshots) {
+ // For low RAM devices, we use the splash screen starting window instead of the
+ // task snapshot starting window.
+ return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+ }
return snapshot == null ? STARTING_WINDOW_TYPE_NONE
: snapshotOrientationSameAsTask(snapshot) || fromRecents
? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 5b20af3534c4..9bc8462c66e3 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -62,7 +62,8 @@ public class BarController {
private StatusBarManagerInternal mStatusBarInternal;
protected WindowState mWin;
- private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
+ private @StatusBarManager.WindowVisibleState int mState =
+ StatusBarManager.WINDOW_STATE_SHOWING;
private int mTransientBarState;
private boolean mPendingShow;
private long mLastTranslucent;
@@ -199,7 +200,8 @@ public class BarController {
return !mWin.isDrawnLw();
}
- private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+ private @StatusBarManager.WindowVisibleState int computeStateLw(
+ boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
if (win.isDrawnLw()) {
final boolean vis = win.isVisibleLw();
final boolean anim = win.isAnimatingLw();
@@ -218,7 +220,7 @@ public class BarController {
return mState;
}
- private boolean updateStateLw(final int state) {
+ private boolean updateStateLw(@StatusBarManager.WindowVisibleState final int state) {
if (mWin != null && state != mState) {
mState = state;
if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a5ceee268fa2..fecc8da3d645 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2506,6 +2506,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWmService.mAnimator.removeDisplayLocked(mDisplayId);
mWindowingLayer.release();
mOverlayLayer.release();
+ mInputMonitor.onDisplayRemoved();
} finally {
mDisplayReady = false;
mRemovingDisplay = false;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 45d77dee1851..5cfa7dec386e 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -326,15 +326,11 @@ class DisplayWindowSettings {
void applySettingsToDisplayLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
+ final Entry entry = getOrCreateEntry(displayInfo);
// Setting windowing mode first, because it may override overscan values later.
dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId()));
- if (entry == null) {
- return;
- }
-
displayInfo.overscanLeft = entry.mOverscanLeft;
displayInfo.overscanTop = entry.mOverscanTop;
displayInfo.overscanRight = entry.mOverscanRight;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index fc1c65cf5807..632db3842839 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -32,6 +32,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITION
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
@@ -45,7 +46,9 @@ import android.view.InputChannel;
import android.view.InputEventReceiver;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
@@ -60,6 +63,7 @@ final class InputMonitor {
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
+ private boolean mUpdateInputWindowsPending;
// Currently focused input window handle.
private InputWindowHandle mFocusedInputWindowHandle;
@@ -70,8 +74,11 @@ final class InputMonitor {
new UpdateInputForAllWindowsConsumer();
private final int mDisplayId;
+ private final DisplayContent mDisplayContent;
+ private boolean mDisplayRemoved;
private final SurfaceControl.Transaction mInputTransaction;
+ private final Handler mHandler;
/**
* The set of input consumer added to the window manager by name, which consumes input events
@@ -105,10 +112,64 @@ final class InputMonitor {
}
}
+ private final Runnable mUpdateInputWindows = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mService.mGlobalLock) {
+ mUpdateInputWindowsPending = false;
+ mUpdateInputWindowsNeeded = false;
+
+ if (mDisplayRemoved) {
+ return;
+ }
+
+ // Populate the input window list with information about all of the windows that
+ // could potentially receive input.
+ // As an optimization, we could try to prune the list of windows but this turns
+ // out to be difficult because only the native code knows for sure which window
+ // currently has touch focus.
+
+ // If there's a drag in flight, provide a pseudo-window to catch drag input
+ final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
+ if (inDrag) {
+ if (DEBUG_DRAG) {
+ Log.d(TAG_WM, "Inserting drag window");
+ }
+ mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
+ } else {
+ mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
+ }
+
+ final boolean inPositioning =
+ mService.mTaskPositioningController.isPositioningLocked();
+ if (inPositioning) {
+ if (DEBUG_TASK_POSITIONING) {
+ Log.d(TAG_WM, "Inserting window handle for repositioning");
+ }
+ mService.mTaskPositioningController.showInputSurface(mInputTransaction,
+ mDisplayId);
+ } else {
+ mService.mTaskPositioningController.hideInputSurface(mInputTransaction,
+ mDisplayId);
+ }
+
+ // Add all windows on the default display.
+ mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
+ }
+ }
+ };
+
public InputMonitor(WindowManagerService service, int displayId) {
mService = service;
+ mDisplayContent = mService.mRoot.getDisplayContent(displayId);
mDisplayId = displayId;
- mInputTransaction = mService.mRoot.getDisplayContent(mDisplayId).getPendingTransaction();
+ mInputTransaction = mDisplayContent.getPendingTransaction();
+ mHandler = AnimationThread.getHandler();
+ }
+
+ void onDisplayRemoved() {
+ mHandler.removeCallbacks(mUpdateInputWindows);
+ mDisplayRemoved = true;
}
private void addInputConsumer(String name, InputConsumerImpl consumer) {
@@ -248,41 +309,18 @@ final class InputMonitor {
if (!force && !mUpdateInputWindowsNeeded) {
return;
}
- mUpdateInputWindowsNeeded = false;
-
- if (false) Slog.d(TAG_WM, ">>>>>> ENTERED updateInputWindowsLw");
-
- // Populate the input window list with information about all of the windows that
- // could potentially receive input.
- // As an optimization, we could try to prune the list of windows but this turns
- // out to be difficult because only the native code knows for sure which window
- // currently has touch focus.
+ scheduleUpdateInputWindows();
+ }
- // If there's a drag in flight, provide a pseudo-window to catch drag input
- final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
- if (inDrag) {
- if (DEBUG_DRAG) {
- Log.d(TAG_WM, "Inserting drag window");
- }
- mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
- } else {
- mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
+ private void scheduleUpdateInputWindows() {
+ if (mDisplayRemoved) {
+ return;
}
- final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked();
- if (inPositioning) {
- if (DEBUG_TASK_POSITIONING) {
- Log.d(TAG_WM, "Inserting window handle for repositioning");
- }
- mService.mTaskPositioningController.showInputSurface(mInputTransaction, mDisplayId);
- } else {
- mService.mTaskPositioningController.hideInputSurface(mInputTransaction, mDisplayId);
+ if (!mUpdateInputWindowsPending) {
+ mUpdateInputWindowsPending = true;
+ mHandler.post(mUpdateInputWindows);
}
-
- // Add all windows on the default display.
- mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
-
- if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw");
}
/* Called when the current input focus changes.
@@ -385,19 +423,18 @@ final class InputMonitor {
mTmpRect.setEmpty();
mDisableWallpaperTouchEvents = false;
this.inDrag = inDrag;
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
- wallpaperController = dc.mWallpaperController;
+ wallpaperController = mDisplayContent.mWallpaperController;
resetInputConsumers(mInputTransaction);
- dc.forAllWindows(this,
+ mDisplayContent.forAllWindows(this,
true /* traverseTopToBottom */);
if (mAddWallpaperInputConsumerHandle) {
wallpaperInputConsumer.show(mInputTransaction, 0);
}
- dc.scheduleAnimation();
+ mDisplayContent.scheduleAnimation();
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 282838f7d58b..fbb9e2905697 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -18,15 +18,16 @@ package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -47,8 +48,18 @@ class InsetsSourceProvider {
private WindowState mWin;
private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
+ /** The visibility override from the current controlling window. */
+ private boolean mClientVisible;
+
+ /**
+ * Whether the window is available and considered visible as in {@link WindowState#isVisible}.
+ */
+ private boolean mServerVisible;
+
+
InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
DisplayContent displayContent) {
+ mClientVisible = InsetsState.getDefaultVisibly(source.getType());
mSource = source;
mDisplayContent = displayContent;
mStateController = stateController;
@@ -73,10 +84,9 @@ class InsetsSourceProvider {
mWin = win;
mFrameProvider = frameProvider;
if (win == null) {
- mSource.setVisible(false);
+ setServerVisible(false);
mSource.setFrame(new Rect());
} else {
- mSource.setVisible(true);
mWin.setInsetProvider(this);
}
}
@@ -96,8 +106,8 @@ class InsetsSourceProvider {
mTmpRect.inset(mWin.mGivenContentInsets);
}
mSource.setFrame(mTmpRect);
- mSource.setVisible(mWin.isVisible() && !mWin.mGivenInsetsPending);
-
+ setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.mPolicyVisibility
+ && !mWin.mGivenInsetsPending);
}
void updateControlForTarget(@Nullable WindowState target) {
@@ -105,26 +115,50 @@ class InsetsSourceProvider {
return;
}
if (target == null) {
- revokeControl();
+ // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
+ mWin.cancelAnimation();
return;
}
mAdapter = new ControlAdapter();
mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
- false /* TODO hidden */);
+ !mClientVisible /* hidden */);
mControllingWin = target;
mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash);
}
+ boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
+ if (mControllingWin != caller || modifiedSource.isVisible() == mClientVisible) {
+ return false;
+ }
+ setClientVisible(modifiedSource.isVisible());
+ return true;
+ }
+
+ private void setClientVisible(boolean clientVisible) {
+ if (mClientVisible == clientVisible) {
+ return;
+ }
+ mClientVisible = clientVisible;
+ mDisplayContent.mWmService.mH.sendMessage(PooledLambda.obtainMessage(
+ DisplayContent::layoutAndAssignWindowLayersIfNeeded, mDisplayContent));
+ updateVisibility();
+ }
+
+ private void setServerVisible(boolean serverVisible) {
+ mServerVisible = serverVisible;
+ updateVisibility();
+ }
+
+ private void updateVisibility() {
+ mSource.setVisible(mServerVisible && mClientVisible);
+ }
+
InsetsSourceControl getControl() {
return mControl;
}
- void revokeControl() {
- if (mControllingWin != null) {
-
- // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
- mWin.cancelAnimation();
- }
+ boolean isClientVisible() {
+ return mClientVisible;
}
private class ControlAdapter implements AnimationAdapter {
@@ -152,6 +186,7 @@ class InsetsSourceProvider {
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mAdapter == this) {
mStateController.notifyControlRevoked(mControllingWin, InsetsSourceProvider.this);
+ setClientVisible(InsetsState.getDefaultVisibly(mSource.getType()));
mControl = null;
mControllingWin = null;
mAdapter = null;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 592b7fba4bfd..cc57b932092c 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.ViewRootImpl;
@@ -117,6 +118,21 @@ class InsetsStateController {
}
}
+ void onInsetsModified(WindowState windowState, InsetsState state) {
+ boolean changed = false;
+ for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
+ final InsetsSource source = state.sourceAt(i);
+ final InsetsSourceProvider provider = mControllers.get(source.getType());
+ if (provider == null) {
+ continue;
+ }
+ changed |= provider.onInsetsModified(windowState, source);
+ }
+ if (changed) {
+ notifyInsetsChanged();
+ }
+ }
+
void onImeTargetChanged(@Nullable WindowState imeTarget) {
onControlChanged(TYPE_IME, imeTarget);
notifyPendingInsetsControlChanged();
@@ -202,5 +218,11 @@ class InsetsStateController {
void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "WindowInsetsStateController");
mState.dump(prefix + " ", pw);
+ pw.println(prefix + " " + "Control map:");
+ for (int i = mTypeWinControlMap.size() - 1; i >= 0; i--) {
+ pw.print(prefix + " ");
+ pw.println(InsetsState.typeToString(mTypeWinControlMap.keyAt(i)) + " -> "
+ + mTypeWinControlMap.valueAt(i));
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 6f92e647d301..f55c7c96e325 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -29,8 +29,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -915,6 +913,13 @@ class RootActivityContainer extends ConfigurationContainer
+ " to its current displayId=" + displayId);
}
+ if (activityDisplay.isSingleTaskInstance() && activityDisplay.getChildCount() > 0) {
+ // We don't allow moving stacks to single instance display that already has a child.
+ Slog.e(TAG, "Can not move stack=" + stack
+ + " to single task instance display=" + activityDisplay);
+ return;
+ }
+
stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
// TODO(multi-display): resize stacks properly if moved from split-screen.
}
@@ -2301,42 +2306,7 @@ class RootActivityContainer extends ConfigurationContainer
for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = display.getChildAt(stackNdx);
pw.println();
- pw.println(" Stack #" + stack.mStackId
- + ": type=" + activityTypeToString(stack.getActivityType())
- + " mode=" + windowingModeToString(stack.getWindowingMode()));
- pw.println(" isSleeping=" + stack.shouldSleepActivities());
- pw.println(" mBounds=" + stack.getRequestedOverrideBounds());
-
- printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
- needSep);
-
- printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false,
- !dumpAll, false, dumpPackage, true,
- " Running activities (most recent first):", null);
-
- needSep = printed;
- boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
- " mPausingActivity: ");
- if (pr) {
- printed = true;
- needSep = false;
- }
- pr = printThisActivity(pw, stack.getResumedActivity(), dumpPackage, needSep,
- " mResumedActivity: ");
- if (pr) {
- printed = true;
- needSep = false;
- }
- if (dumpAll) {
- pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
- " mLastPausedActivity: ");
- if (pr) {
- printed = true;
- needSep = true;
- }
- printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
- needSep, " mLastNoHistoryActivity: ");
- }
+ printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
needSep = printed;
}
printThisActivity(pw, activityDisplay.getResumedActivity(), dumpPackage, needSep,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 37b5a7c30218..d85fdb03e4a6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -430,6 +430,18 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
}
+ @Override
+ public void insetsModified(IWindow window, InsetsState state) {
+ synchronized (mService.mWindowMap) {
+ final WindowState windowState = mService.windowForClientLocked(this, window,
+ false /* throwOnError */);
+ if (windowState != null) {
+ windowState.getDisplayContent().getInsetsStateController().onInsetsModified(
+ windowState, state);
+ }
+ }
+ }
+
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 5107b522c33b..6acd8641271c 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -219,10 +219,16 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
}
}
- if (launchMode == WINDOWING_MODE_FREEFORM && !currentParams.mBounds.isEmpty()) {
+ if (!currentParams.mBounds.isEmpty()) {
+ // Carry over bounds from callers regardless of launch mode because bounds is still
+ // used to restore last non-fullscreen bounds when launch mode is not freeform.
+ // Therefore it's not a resolution step for non-freeform launch mode and only
+ // consider it fully resolved only when launch mode is freeform.
outParams.mBounds.set(currentParams.mBounds);
- fullyResolvedCurrentParam = true;
- if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+ if (launchMode == WINDOWING_MODE_FREEFORM) {
+ fullyResolvedCurrentParam = true;
+ if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+ }
}
}
@@ -305,6 +311,13 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
displayId = optionLaunchId;
}
+ // If the source activity is a no-display activity, pass on the launch display id from
+ // source activity as currently preferred.
+ if (displayId == INVALID_DISPLAY && source != null && source.noDisplay) {
+ displayId = source.mHandoverLaunchDisplayId;
+ if (DEBUG) appendLog("display-from-no-display-source=" + displayId);
+ }
+
ActivityStack stack =
(displayId == INVALID_DISPLAY && task != null) ? task.getStack() : null;
if (stack != null) {
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 8c800097e49d..e3433228f2de 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -481,6 +481,32 @@ class TaskRecord extends ConfigurationContainer {
mTask = task;
}
+ void cleanUpResourcesForDestroy() {
+ if (!mActivities.isEmpty()) {
+ return;
+ }
+
+ // This task is going away, so save the last state if necessary.
+ saveLaunchingStateIfNeeded();
+
+ // TODO: VI what about activity?
+ final boolean isVoiceSession = voiceSession != null;
+ if (isVoiceSession) {
+ try {
+ voiceSession.taskFinished(intent, taskId);
+ } catch (RemoteException e) {
+ }
+ }
+ if (autoRemoveFromRecents() || isVoiceSession) {
+ // Task creator asked to remove this when done, or this task was a voice
+ // interaction, so it should not remain on the recent tasks list.
+ mService.mStackSupervisor.mRecentTasks.remove(this);
+ }
+
+ removeWindowContainer();
+ }
+
+ @VisibleForTesting
void removeWindowContainer() {
mService.getLockTaskController().clearLockedTask(this);
if (mTask == null) {
@@ -885,7 +911,6 @@ class TaskRecord extends ConfigurationContainer {
info.packageName, info.targetActivity);
if (_intent != null) {
Intent targetIntent = new Intent(_intent);
- targetIntent.setComponent(targetComponent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
if (DEBUG_TASKS) Slog.v(TAG_TASKS,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b6a4a51c41f2..f5f55e2ebf73 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -433,6 +433,12 @@ public class WindowManagerService extends IWindowManager.Stub
final long mDrawLockTimeoutMillis;
final boolean mAllowAnimationsInLowPowerMode;
+ /**
+ * Use very low resolution task snapshots. Replaces task snapshot starting windows with
+ * splashscreen starting windows. Used on low RAM devices to save memory.
+ */
+ final boolean mLowRamTaskSnapshots;
+
final boolean mAllowBootMessages;
final boolean mLimitedAlphaCompositing;
@@ -949,6 +955,8 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_disableTransitionAnimation);
mPerDisplayFocusEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_perDisplayFocusEnabled);
+ mLowRamTaskSnapshots = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_lowRamTaskSnapshotsAndRecents);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplayWindowSettings = new DisplayWindowSettings(this);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index f7f7528c5234..c38a974ac774 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -141,6 +141,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private volatile boolean mPerceptible;
// Set to true when process was launched with a wrapper attached
private volatile boolean mUsingWrapper;
+ // Set to true if this process is currently temporarily whitelisted to start activities even if
+ // it's not in the foreground
+ private volatile boolean mAllowBackgroundActivityStarts;
// Thread currently set for VR scheduling
int mVrThreadTid;
@@ -343,6 +346,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mUsingWrapper;
}
+ public void setAllowBackgroundActivityStarts(boolean allowBackgroundActivityStarts) {
+ mAllowBackgroundActivityStarts = allowBackgroundActivityStarts;
+ }
+
+ public boolean areBackgroundActivityStartsAllowed() {
+ return mAllowBackgroundActivityStarts;
+ }
+
public void setInstrumenting(boolean instrumenting) {
mInstrumenting = instrumenting;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e78c12cfcc78..cd29b3c29248 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1373,12 +1373,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean isVisible() {
- return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility;
+ return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility
+ // If we don't have a provider, this window isn't used as a window generating
+ // insets, so nobody can hide it over the inset APIs.
+ && (mInsetProvider == null || mInsetProvider.isClientVisible());
}
/**
- * @return True if the window would be visible if we'd ignore policy visibility, false
- * otherwise.
+ * @return {@code true} if the window would be visible if we'd ignore policy visibility,
+ * {@code false} otherwise.
*/
boolean wouldBeVisibleIfPolicyIgnored() {
return mHasSurface && !isParentWindowHidden()
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 6d7219173b32..b4fe83704ff2 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -111,6 +111,7 @@ cc_defaults {
"android.hardware.light@2.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
+ "android.hardware.power.stats@1.0",
"android.hardware.tetheroffload.config@1.0",
"android.hardware.thermal@1.0",
"android.hardware.tv.cec@1.0",
diff --git a/services/core/jni/BroadcastRadio/NativeCallbackThread.h b/services/core/jni/BroadcastRadio/NativeCallbackThread.h
index 53990be06535..0f62de9c39df 100644
--- a/services/core/jni/BroadcastRadio/NativeCallbackThread.h
+++ b/services/core/jni/BroadcastRadio/NativeCallbackThread.h
@@ -41,7 +41,7 @@ class NativeCallbackThread {
DISALLOW_COPY_AND_ASSIGN(NativeCallbackThread);
public:
- NativeCallbackThread(JavaVM *vm);
+ explicit NativeCallbackThread(JavaVM *vm);
virtual ~NativeCallbackThread();
void enqueue(const Task &task);
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 9c2e1e59dd32..a2a7f7d9645d 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -73,7 +73,8 @@ class HalDeathRecipient : public hidl_death_recipient {
wp<V1_1::ITunerCallback> mTunerCallback;
public:
- HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback):mTunerCallback(tunerCallback) {}
+ explicit HalDeathRecipient(wp<V1_1::ITunerCallback> tunerCallback)
+ : mTunerCallback(tunerCallback) {}
virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who);
};
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 0ff60e44b0ce..024760d46760 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -27,9 +27,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <unordered_map>
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
#include <android_runtime/AndroidRuntime.h>
@@ -74,6 +76,33 @@ static jmethodID jgetSubsystem = NULL;
static jmethodID jputVoter = NULL;
static jmethodID jputState = NULL;
+std::mutex gPowerHalMutex;
+std::unordered_map<uint32_t, std::string> gPowerStatsHalEntityNames = {};
+std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>>
+ gPowerStatsHalStateNames = {};
+std::vector<uint32_t> gPowerStatsHalPlatformIds = {};
+std::vector<uint32_t> gPowerStatsHalSubsystemIds = {};
+sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
+std::function<void(JNIEnv*, jobject)> gGetLowPowerStatsImpl = {};
+std::function<jint(JNIEnv*, jobject)> gGetPlatformLowPowerStatsImpl = {};
+std::function<jint(JNIEnv*, jobject)> gGetSubsystemLowPowerStatsImpl = {};
+
+// The caller must be holding gPowerHalMutex.
+static void deinitPowerStatsLocked() {
+ gPowerStatsHalV1_0 = nullptr;
+}
+
+struct PowerHalDeathRecipient : 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(gPowerHalMutex);
+ deinitPowerStatsLocked();
+ }
+};
+
+sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
+
class WakeupCallback : public ISystemSuspendCallback {
public:
Return<void> notifyWakeup(bool success) override {
@@ -202,18 +231,291 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf)
return mergedreasonpos - mergedreason;
}
-static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats) {
- if (jrpmStats == NULL) {
- jniThrowException(env, "java/lang/NullPointerException",
- "The rpmstats jni input jobject jrpmStats is null.");
- return;
+// The caller must be holding gPowerHalMutex.
+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());
+ if (ret.isDeadObject()) {
+ deinitPowerStatsLocked();
+ }
+ return false;
}
- if (jgetAndUpdatePlatformState == NULL || jgetSubsystem == NULL
- || jputVoter == NULL || jputState == NULL) {
- ALOGE("A rpmstats jni jmethodID is null.");
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+// gPowerStatsHalV1_0 must not be null
+static bool initializePowerStats() {
+ using android::hardware::power::stats::V1_0::Status;
+ using android::hardware::power::stats::V1_0::PowerEntityType;
+
+ // Clear out previous content if we are re-initializing
+ gPowerStatsHalEntityNames.clear();
+ gPowerStatsHalStateNames.clear();
+ gPowerStatsHalPlatformIds.clear();
+ gPowerStatsHalSubsystemIds.clear();
+
+ Return<void> ret;
+ ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId to power entity name
+ // also construct vector of platform and subsystem IDs
+ for (auto info : infos) {
+ gPowerStatsHalEntityNames.emplace(info.powerEntityId, info.powerEntityName);
+ if (info.type == PowerEntityType::POWER_DOMAIN) {
+ gPowerStatsHalPlatformIds.emplace_back(info.powerEntityId);
+ } else {
+ gPowerStatsHalSubsystemIds.emplace_back(info.powerEntityId);
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
+ ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting state info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
+ for (auto stateSpace : stateSpaces) {
+ std::unordered_map<uint32_t, std::string> stateNames = {};
+ for (auto state : stateSpace.states) {
+ stateNames.emplace(state.powerEntityStateId,
+ state.powerEntityStateName);
+ }
+ gPowerStatsHalStateNames.emplace(stateSpace.powerEntityId, stateNames);
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
+ return (!gPowerStatsHalEntityNames.empty()) && (!gPowerStatsHalStateNames.empty());
+}
+
+// The caller must be holding gPowerHalMutex.
+static bool getPowerStatsHalLocked() {
+ if (gPowerStatsHalV1_0 == nullptr) {
+ gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
+ if (gPowerStatsHalV1_0 == nullptr) {
+ ALOGE("Unable to get power.stats HAL service.");
+ return false;
+ }
+
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ deinitPowerStatsLocked();
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ // We should still continue even though linking failed
+ }
+ return initializePowerStats();
+ }
+ return true;
+}
+
+// The caller must be holding powerHalMutex.
+static void getPowerStatsHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
+ using android::hardware::power::stats::V1_0::Status;
+
+ if (!getPowerStatsHalLocked()) {
+ ALOGE("failed to get low power stats");
return;
}
+ // Get power entity state residency data
+ bool success = false;
+ Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
+ [&env, &jrpmStats, &success](auto results, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getPowerEntityStateResidencyData is not supported");
+ success = false;
+ return;
+ }
+
+ for (auto result : results) {
+ jobject jsubsystem = env->CallObjectMethod(jrpmStats, jgetSubsystem,
+ env->NewStringUTF(gPowerStatsHalEntityNames.at(result.powerEntityId).c_str()));
+ if (jsubsystem == NULL) {
+ ALOGE("The rpmstats jni jobject jsubsystem is null.");
+ return;
+ }
+ for (auto stateResidency : result.stateResidencyData) {
+
+ env->CallVoidMethod(jsubsystem, jputState,
+ env->NewStringUTF(gPowerStatsHalStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId).c_str()),
+ stateResidency.totalTimeInStateMs,
+ stateResidency.totalStateEntryCount);
+ }
+ }
+ success = true;
+ });
+ checkResultLocked(ret, __func__);
+ if (!success) {
+ ALOGE("getPowerEntityStateResidencyData failed");
+ }
+}
+
+static jint getPowerStatsHalPlatformData(JNIEnv* env, jobject outBuf) {
+ using android::hardware::power::stats::V1_0::Status;
+ using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+ using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
+
+ if (!getPowerStatsHalLocked()) {
+ ALOGE("failed to get low power stats");
+ return -1;
+ }
+
+ char *output = (char*)env->GetDirectBufferAddress(outBuf);
+ char *offset = output;
+ int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+ int total_added = -1;
+
+ // Get power entity state residency data
+ Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
+ gPowerStatsHalPlatformIds,
+ [&offset, &remaining, &total_added](auto results, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getPowerEntityStateResidencyData is not supported");
+ return;
+ }
+
+ for (size_t i = 0; i < results.size(); i++) {
+ const PowerEntityStateResidencyResult& result = results[i];
+
+ for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
+ const PowerEntityStateResidencyData& stateResidency =
+ result.stateResidencyData[j];
+ int added = snprintf(offset, remaining,
+ "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
+ j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId).c_str(),
+ stateResidency.totalTimeInStateMs,
+ stateResidency.totalStateEntryCount);
+ if (added < 0) {
+ break;
+ }
+ if (added > remaining) {
+ added = remaining;
+ }
+ offset += added;
+ remaining -= added;
+ total_added += added;
+ }
+ if (remaining <= 0) {
+ /* rewrite NULL character*/
+ offset--;
+ total_added--;
+ ALOGE("power.stats Hal: buffer not enough");
+ break;
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return -1;
+ }
+
+ total_added += 1;
+ return total_added;
+}
+
+static jint getPowerStatsHalSubsystemData(JNIEnv* env, jobject outBuf) {
+ using android::hardware::power::stats::V1_0::Status;
+ using hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+ using hardware::power::stats::V1_0::PowerEntityStateResidencyData;
+
+ if (!getPowerStatsHalLocked()) {
+ ALOGE("failed to get low power stats");
+ return -1;
+ }
+
+ char *output = (char*)env->GetDirectBufferAddress(outBuf);
+ char *offset = output;
+ int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+ int total_added = -1;
+
+ // Get power entity state residency data
+ Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
+ gPowerStatsHalSubsystemIds,
+ [&offset, &remaining, &total_added](auto results, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getPowerEntityStateResidencyData is not supported");
+ return;
+ }
+
+ int added = snprintf(offset, remaining, "SubsystemPowerState ");
+ offset += added;
+ remaining -= added;
+ total_added += added;
+
+ for (size_t i = 0; i < results.size(); i++) {
+ const PowerEntityStateResidencyResult& result = results[i];
+ added = snprintf(offset, remaining, "subsystem_%zu name=%s ",
+ i + 1, gPowerStatsHalEntityNames.at(result.powerEntityId).c_str());
+ if (added < 0) {
+ break;
+ }
+
+ if (added > remaining) {
+ added = remaining;
+ }
+
+ offset += added;
+ remaining -= added;
+ total_added += added;
+
+ for (size_t j = 0; j < result.stateResidencyData.size(); j++) {
+ const PowerEntityStateResidencyData& stateResidency =
+ result.stateResidencyData[j];
+ added = snprintf(offset, remaining,
+ "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry=%"
+ PRIu64 " ", j + 1, gPowerStatsHalStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId).c_str(),
+ stateResidency.totalTimeInStateMs,
+ stateResidency.totalStateEntryCount,
+ stateResidency.lastEntryTimestampMs);
+ if (added < 0) {
+ break;
+ }
+ if (added > remaining) {
+ added = remaining;
+ }
+ offset += added;
+ remaining -= added;
+ total_added += added;
+ }
+ if (remaining <= 0) {
+ /* rewrite NULL character*/
+ offset--;
+ total_added--;
+ ALOGE("power.stats Hal: buffer not enough");
+ break;
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return -1;
+ }
+
+ total_added += 1;
+ return total_added;
+}
+
+// The caller must be holding powerHalMutex.
+static void getPowerHalLowPowerData(JNIEnv* env, jobject jrpmStats) {
sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
if (powerHalV1_0 == nullptr) {
ALOGE("Power Hal not loaded");
@@ -286,17 +588,12 @@ static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats
processPowerHalReturn(ret, "getSubsystemLowPowerStats");
}
-static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+static jint getPowerHalPlatformData(JNIEnv* env, jobject outBuf) {
char *output = (char*)env->GetDirectBufferAddress(outBuf);
char *offset = output;
int remaining = (int)env->GetDirectBufferCapacity(outBuf);
int total_added = -1;
- if (outBuf == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", "null argument");
- return -1;
- }
-
{
sp<IPowerV1_0> powerHalV1_0 = getPowerHalV1_0();
if (powerHalV1_0 == nullptr) {
@@ -365,7 +662,7 @@ static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject o
return total_added;
}
-static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+static jint getPowerHalSubsystemData(JNIEnv* env, jobject outBuf) {
char *output = (char*)env->GetDirectBufferAddress(outBuf);
char *offset = output;
int remaining = (int)env->GetDirectBufferCapacity(outBuf);
@@ -374,11 +671,6 @@ static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject
// This is a IPower 1.1 API
sp<IPowerV1_1> powerHal_1_1 = nullptr;
- if (outBuf == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", "null argument");
- return -1;
- }
-
{
// Trying to get 1.1, this will succeed only for devices supporting 1.1
powerHal_1_1 = getPowerHalV1_1();
@@ -458,6 +750,88 @@ static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject
return total_added;
}
+static void setUpPowerStatsLocked() {
+ // First see if power.stats HAL is available. Fall back to power HAL if
+ // power.stats HAL is unavailable.
+ if (android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
+ ALOGI("Using power.stats HAL");
+ gGetLowPowerStatsImpl = getPowerStatsHalLowPowerData;
+ gGetPlatformLowPowerStatsImpl = getPowerStatsHalPlatformData;
+ gGetSubsystemLowPowerStatsImpl = getPowerStatsHalSubsystemData;
+ } else if (android::hardware::power::V1_0::IPower::getService() != nullptr) {
+ ALOGI("Using power HAL");
+ gGetLowPowerStatsImpl = getPowerHalLowPowerData;
+ gGetPlatformLowPowerStatsImpl = getPowerHalPlatformData;
+ gGetSubsystemLowPowerStatsImpl = getPowerHalSubsystemData;
+ }
+}
+
+static void getLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject jrpmStats) {
+ if (jrpmStats == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException",
+ "The rpmstats jni input jobject jrpmStats is null.");
+ return;
+ }
+ if (jgetAndUpdatePlatformState == NULL || jgetSubsystem == NULL
+ || jputVoter == NULL || jputState == NULL) {
+ ALOGE("A rpmstats jni jmethodID is null.");
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!gGetLowPowerStatsImpl) {
+ setUpPowerStatsLocked();
+ }
+
+ if (gGetLowPowerStatsImpl) {
+ return gGetLowPowerStatsImpl(env, jrpmStats);
+ }
+
+ ALOGE("Unable to load Power Hal or power.stats HAL");
+ return;
+}
+
+static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+ if (outBuf == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "null argument");
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!gGetPlatformLowPowerStatsImpl) {
+ setUpPowerStatsLocked();
+ }
+
+ if (gGetPlatformLowPowerStatsImpl) {
+ return gGetPlatformLowPowerStatsImpl(env, outBuf);
+ }
+
+ ALOGE("Unable to load Power Hal or power.stats HAL");
+ return -1;
+}
+
+static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+ if (outBuf == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "null argument");
+ return -1;
+ }
+
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!gGetSubsystemLowPowerStatsImpl) {
+ setUpPowerStatsLocked();
+ }
+
+ if (gGetSubsystemLowPowerStatsImpl) {
+ return gGetSubsystemLowPowerStatsImpl(env, outBuf);
+ }
+
+ ALOGE("Unable to load Power Hal or power.stats HAL");
+ return -1;
+}
+
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
{ "getLowPowerStats", "(Lcom/android/internal/os/RpmStats;)V", (void*)getLowPowerStats },
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index c22109c7816a..b08d13f234ce 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -89,7 +89,7 @@ public:
private:
class HdmiCecCallback : public IHdmiCecCallback {
public:
- HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
+ explicit HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
Return<void> onCecMessage(const CecMessage& event) override;
Return<void> onHotplugEvent(const HotplugEvent& event) override;
private:
diff --git a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
index c8f842dde7ae..e51963340ae1 100644
--- a/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
+++ b/services/core/jni/com_android_server_storage_AppFuseBridge.cpp
@@ -74,7 +74,7 @@ public:
}
}
- operator bool() {
+ explicit operator bool() {
return mLocked;
}
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 6c2a894a3a6a..098b2ef6439d 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -292,7 +292,7 @@ private:
class TvInputCallback : public ITvInputCallback {
public:
- TvInputCallback(JTvInputHal* hal);
+ explicit TvInputCallback(JTvInputHal* hal);
Return<void> notify(const TvInputEvent& event) override;
private:
JTvInputHal* mHal;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 333b3e37ff2a..be09aea65073 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -123,6 +123,7 @@ import com.android.server.power.ShutdownThread;
import com.android.server.power.ThermalManagerService;
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
+import com.android.server.rollback.RollbackManagerService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
import com.android.server.signedconfig.SignedConfigService;
@@ -779,6 +780,11 @@ public final class SystemServer {
traceBeginAndSlog("StartLooperStatsService");
mSystemServiceManager.startService(LooperStatsService.Lifecycle.class);
traceEnd();
+
+ // Manages apk rollbacks.
+ traceBeginAndSlog("StartRollbackManagerService");
+ mSystemServiceManager.startService(RollbackManagerService.class);
+ traceEnd();
}
/**
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index b8723c520cf8..b682def9c224 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows;
@@ -192,6 +193,19 @@ public class BackupManagerServiceTest {
/** Test that the service unregisters users when stopped. */
@Test
+ public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
+ BackupManagerService backupManagerService =
+ createServiceAndRegisterUser(mUserOneId, mUserOneService);
+ backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+
+ backupManagerService.stopServiceForUser(mUserOneId);
+
+ verify(mUserOneService).tearDownService();
+ verifyNoMoreInteractions(mUserTwoService);
+ }
+
+ /** Test that the service unregisters users when stopped. */
+ @Test
public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
BackupManagerService backupManagerService = createService();
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index bb60c27a2543..c65830d37d33 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -970,9 +970,8 @@ public class UserBackupManagerServiceTest {
}
/**
- * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
- * Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task
- * to the backup thread.
+ * Test verifying that creating a new instance posts a transport registration task to the backup
+ * thread.
*/
@Test
public void testCreateAndInitializeService_postRegisterTransports() {
@@ -992,9 +991,8 @@ public class UserBackupManagerServiceTest {
}
/**
- * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
- * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register
- * transports on the main thread.
+ * Test verifying that creating a new instance does not directly register transports on the main
+ * thread.
*/
@Test
public void testCreateAndInitializeService_doesNotRegisterTransportsSynchronously() {
@@ -1013,11 +1011,7 @@ public class UserBackupManagerServiceTest {
verify(mTransportManager, never()).registerTransports();
}
- /**
- * Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
- * File, TransportManager)}.
- */
+ /** Test checking non-null argument on instance creation. */
@Test
public void testCreateAndInitializeService_withNullContext_throws() {
expectThrows(
@@ -1033,11 +1027,7 @@ public class UserBackupManagerServiceTest {
mTransportManager));
}
- /**
- * Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
- * File, TransportManager)}.
- */
+ /** Test checking non-null argument on instance creation. */
@Test
public void testCreateAndInitializeService_withNullTrampoline_throws() {
expectThrows(
@@ -1053,11 +1043,7 @@ public class UserBackupManagerServiceTest {
mTransportManager));
}
- /**
- * Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
- * File, TransportManager)}.
- */
+ /** Test checking non-null argument on instance creation. */
@Test
public void testCreateAndInitializeService_withNullBackupThread_throws() {
expectThrows(
@@ -1073,11 +1059,7 @@ public class UserBackupManagerServiceTest {
mTransportManager));
}
- /**
- * Test checking non-null argument on {@link
- * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
- * File, TransportManager)}.
- */
+ /** Test checking non-null argument on instance creation. */
@Test
public void testCreateAndInitializeService_withNullStateDir_throws() {
expectThrows(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 767eb60de4f8..6a10ff487d2d 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -29,6 +29,8 @@ import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.util.DebugUtils.valueToString;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG;
import static com.android.server.am.ActivityManagerService.Injector;
@@ -69,6 +71,9 @@ import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import com.android.server.AppOpsService;
+import com.android.server.am.ProcessList.IsolatedUidRange;
+import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
+import com.android.server.wm.ActivityTaskManagerService;
import org.junit.After;
import org.junit.Before;
@@ -109,7 +114,7 @@ public class ActivityManagerServiceTest {
UidRecord.CHANGE_ACTIVE
};
- @Mock private Context mContext;
+ private Context mContext = getInstrumentation().getTargetContext();
@Mock private AppOpsService mAppOpsService;
@Mock private PackageManager mPackageManager;
@@ -128,8 +133,8 @@ public class ActivityManagerServiceTest {
mInjector = new TestInjector();
mAms = new ActivityManagerService(mInjector);
mAms.mWaitForNetworkTimeoutMs = 2000;
-
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
}
@After
@@ -291,6 +296,113 @@ public class ActivityManagerServiceTest {
}
}
+ private void validateAppZygoteIsolatedUidRange(IsolatedUidRange uidRange) {
+ assertNotNull(uidRange);
+ assertTrue(uidRange.mFirstUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && uidRange.mFirstUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+ assertTrue(uidRange.mLastUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+ && uidRange.mLastUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+ assertTrue(uidRange.mLastUid > uidRange.mFirstUid
+ && ((uidRange.mLastUid - uidRange.mFirstUid + 1)
+ == Process.NUM_UIDS_PER_APP_ZYGOTE));
+ }
+
+ private void verifyUidRangesNoOverlap(IsolatedUidRange uidRange1, IsolatedUidRange uidRange2) {
+ IsolatedUidRange lowRange = uidRange1.mFirstUid <= uidRange2.mFirstUid ? uidRange1 : uidRange2;
+ IsolatedUidRange highRange = lowRange == uidRange1 ? uidRange2 : uidRange1;
+
+ assertTrue(highRange.mFirstUid > lowRange.mLastUid);
+ }
+
+ @Test
+ public void testIsolatedUidRangeAllocator() {
+ final IsolatedUidRangeAllocator allocator = mAms.mProcessList.mAppIsolatedUidRangeAllocator;
+
+ // Create initial range
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.processName = "com.android.test.app";
+ appInfo.uid = 10000;
+ final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+ validateAppZygoteIsolatedUidRange(range);
+ verifyIsolatedUidAllocator(range);
+
+ // Create a second range
+ ApplicationInfo appInfo2 = new ApplicationInfo();
+ appInfo2.processName = "com.android.test.app2";
+ appInfo2.uid = 10001;
+ IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+ validateAppZygoteIsolatedUidRange(range2);
+ verifyIsolatedUidAllocator(range2);
+
+ // Verify ranges don't overlap
+ verifyUidRangesNoOverlap(range, range2);
+
+ // Free range, reallocate and verify
+ allocator.freeUidRangeLocked(appInfo2);
+ range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+ validateAppZygoteIsolatedUidRange(range2);
+ verifyUidRangesNoOverlap(range, range2);
+ verifyIsolatedUidAllocator(range2);
+
+ // Free both, then try to allocate the maximum number of UID ranges
+ allocator.freeUidRangeLocked(appInfo);
+ allocator.freeUidRangeLocked(appInfo2);
+
+ int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID
+ - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE;
+ for (int i = 0; i < maxNumUidRanges; i++) {
+ appInfo = new ApplicationInfo();
+ appInfo.uid = 10000 + i;
+ appInfo.processName = "com.android.test.app" + Integer.toString(i);
+ IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+ validateAppZygoteIsolatedUidRange(uidRange);
+ verifyIsolatedUidAllocator(uidRange);
+ }
+
+ // Try to allocate another one and make sure it fails
+ appInfo = new ApplicationInfo();
+ appInfo.uid = 9000;
+ appInfo.processName = "com.android.test.app.failed";
+ IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+
+ assertNull(failedRange);
+ }
+
+ public void verifyIsolatedUid(ProcessList.IsolatedUidRange range, int uid) {
+ assertTrue(uid >= range.mFirstUid && uid <= range.mLastUid);
+ }
+
+ public void verifyIsolatedUidAllocator(ProcessList.IsolatedUidRange range) {
+ int uid = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid);
+
+ int uid2 = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid2);
+ assertTrue(uid2 != uid);
+
+ // Free both
+ range.freeIsolatedUidLocked(uid);
+ range.freeIsolatedUidLocked(uid2);
+
+ // Allocate the entire range
+ for (int i = 0; i < (range.mLastUid - range.mFirstUid + 1); ++i) {
+ uid = range.allocateIsolatedUidLocked(0);
+ verifyIsolatedUid(range, uid);
+ }
+
+ // Ensure the next one fails
+ uid = range.allocateIsolatedUidLocked(0);
+ assertEquals(uid, -1);
+ }
+
+ @Test
+ public void testGlobalIsolatedUidAllocator() {
+ final IsolatedUidRange globalUidRange = mAms.mProcessList.mGlobalIsolatedUids;
+ assertEquals(globalUidRange.mFirstUid, Process.FIRST_ISOLATED_UID);
+ assertEquals(globalUidRange.mLastUid, Process.LAST_ISOLATED_UID);
+ verifyIsolatedUidAllocator(globalUidRange);
+ }
+
@Test
public void testBlockStateForUid() {
final UidRecord uidRec = new UidRecord(TEST_UID, null /* atmInternal */);
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 0889265dd663..d4bb6369c710 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -193,6 +193,7 @@ public class BroadcastRecordTest {
false /* serialized */,
false /* sticky */,
false /* initialSticky */,
- userId);
+ userId,
+ false /* allowBackgroundActivityStarts */);
}
}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 7a5eaa852c34..f4443fe81a00 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -20,6 +20,7 @@ android_test {
"android-support-test",
"mockito-target-inline-minus-junit4",
"platform-test-annotations",
+ "hamcrest-library",
"testables",
],
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index afbe6bc21d0d..20c5f5dd63dc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -60,6 +60,7 @@ import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -114,7 +115,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.build();
private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
private static final int CUSTOM_LIGHT_ON = 10000;
@@ -237,11 +238,11 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
false /* noisy */, false /* buzzy*/, true /* lights */);
}
- private NotificationRecord getCustomLightsNotification() {
- return getNotificationRecord(mId, false /* insistent */, true /* once */,
- false /* noisy */, true /* buzzy*/, true /* lights */,
- true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */,
- null, Notification.GROUP_ALERT_ALL, false);
+ private NotificationRecord getCallRecord(int id, boolean insistent) {
+ return getNotificationRecord(id, false, false /* once */, true /* noisy */,
+ false /* buzzy */, false /* lights */, false /* default vib */,
+ false /* default sound */, false /* default lights */, "",
+ Notification.GROUP_ALERT_ALL, false);
}
private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
@@ -351,11 +352,6 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
eq(false), (AudioAttributes) anyObject());
}
- private void verifyCustomBeep() throws RemoteException {
- verify(mRingtonePlayer, times(1)).playAsync(eq(CUSTOM_SOUND), (UserHandle) anyObject(),
- eq(false), (AudioAttributes) anyObject());
- }
-
private void verifyNeverStopAudio() throws RemoteException {
verify(mRingtonePlayer, never()).stopAsync();
}
@@ -1277,6 +1273,64 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
assertEquals(-1, group.getLastAudiblyAlertedMs());
}
+ @Test
+ public void testListenerHintCall() throws Exception {
+ NotificationRecord r = getCallRecord(1, true);
+
+ mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ }
+
+ @Test
+ public void testListenerHintCall_notificationSound() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeepLooped();
+ }
+
+ @Test
+ public void testListenerHintNotification() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+
+ mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ }
+
+ @Test
+ public void testListenerHintBoth() throws Exception {
+ NotificationRecord r = getCallRecord(1, true);
+ NotificationRecord s = getBeepyNotification();
+
+ mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
+ | NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+ mService.buzzBeepBlinkLocked(r);
+ mService.buzzBeepBlinkLocked(s);
+
+ verifyNeverBeep();
+ }
+
+ @Test
+ public void testListenerHintNotification_callSound() throws Exception {
+ NotificationRecord r = getCallRecord(1, true);
+
+ mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeepLooped();
+ }
+
static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
private final int mRepeatIndex;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 659c6e7aeed3..8b65e763b088 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -859,6 +859,19 @@ public class ManagedServicesTest extends UiServiceTestCase {
assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
}
+ @Test
+ public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
+ for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+ mIpm, approvalLevel);
+ // null uid list
+ service.onPackagesChanged(true, new String[]{"this.is.a.package.name"}, null);
+
+ // null package list
+ service.onPackagesChanged(true, null, new int[]{103});
+ }
+ }
+
private void loadXml(ManagedServices service) throws Exception {
final StringBuffer xml = new StringBuffer();
xml.append("<" + service.getConfig().xmlTag + ">\n");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
new file mode 100644
index 000000000000..fa90b291eeee
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// this is a lazy way to do in/out/err but we're not particularly interested in the output
+import static java.io.FileDescriptor.err;
+import static java.io.FileDescriptor.in;
+import static java.io.FileDescriptor.out;
+
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.Icon;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class NotificationShellCmdTest extends UiServiceTestCase {
+ private final Binder mBinder = new Binder();
+ private final ShellCallback mCallback = new ShellCallback();
+ private final TestableContext mTestableContext = spy(getContext());
+ @Mock
+ NotificationManagerService mMockService;
+ @Mock
+ INotificationManager mMockBinderService;
+ private TestableLooper mTestableLooper;
+ private ResultReceiver mResultReceiver;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mTestableLooper = TestableLooper.get(this);
+ mResultReceiver = new ResultReceiver(new Handler(mTestableLooper.getLooper()));
+
+ when(mMockService.getContext()).thenReturn(mTestableContext);
+ when(mMockService.getBinderService()).thenReturn(mMockBinderService);
+ }
+
+ private Bitmap createTestBitmap() {
+ final Bitmap bits = Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bits);
+ final GradientDrawable grad = new GradientDrawable(GradientDrawable.Orientation.TL_BR,
+ new int[]{Color.RED, Color.YELLOW, Color.GREEN,
+ Color.CYAN, Color.BLUE, Color.MAGENTA});
+ grad.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ grad.draw(canvas);
+ return bits;
+ }
+
+ private void doCmd(String... args) {
+ new NotificationShellCmd(mMockService)
+ .exec(mBinder, in, out, err, args, mCallback, mResultReceiver);
+ }
+
+ @Test
+ public void testNoArgs() throws Exception {
+ doCmd();
+ }
+
+ @Test
+ public void testHelp() throws Exception {
+ doCmd("--help");
+ }
+
+ Notification captureNotification(String aTag) throws Exception {
+ ArgumentCaptor<Notification> notificationCaptor =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mMockBinderService).enqueueNotificationWithTag(
+ eq(NotificationShellCmd.NOTIFICATION_PACKAGE),
+ eq("android"),
+ eq(aTag),
+ eq(NotificationShellCmd.NOTIFICATION_ID),
+ notificationCaptor.capture(),
+ eq(UserHandle.getCallingUserId()));
+ return notificationCaptor.getValue();
+ }
+
+ @Test
+ public void testBasic() throws Exception {
+ final String aTag = "aTag";
+ final String aText = "someText";
+ final String aTitle = "theTitle";
+ doCmd("notify",
+ "--title", aTitle,
+ aTag, aText);
+ final Notification captured = captureNotification(aTag);
+ assertEquals(aText, captured.extras.getString(Notification.EXTRA_TEXT));
+ assertEquals(aTitle, captured.extras.getString(Notification.EXTRA_TITLE));
+ }
+
+ @Test
+ public void testIcon() throws Exception {
+ final String aTag = "aTag";
+ final String aText = "someText";
+ doCmd("notify", "--icon", "@android:drawable/stat_sys_adb", aTag, aText);
+ final Notification captured = captureNotification(aTag);
+ final Icon icon = captured.getSmallIcon();
+ assertEquals("android", icon.getResPackage());
+ assertEquals(com.android.internal.R.drawable.stat_sys_adb, icon.getResId());
+ }
+
+ @Test
+ public void testBigText() throws Exception {
+ final String aTag = "aTag";
+ final String aText = "someText";
+ final String bigText = "someBigText";
+ doCmd("notify",
+ "--style", "bigtext",
+ "--big-text", bigText,
+ aTag, aText);
+ final Notification captured = captureNotification(aTag);
+ assertSame(captured.getNotificationStyle(), Notification.BigTextStyle.class);
+ assertEquals(aText, captured.extras.getString(Notification.EXTRA_TEXT));
+ assertEquals(bigText, captured.extras.getString(Notification.EXTRA_BIG_TEXT));
+ }
+
+ @Test
+ public void testBigPicture() throws Exception {
+ final String aTag = "aTag";
+ final String aText = "someText";
+ final String bigPicture = "@android:drawable/default_wallpaper";
+ doCmd("notify",
+ "--style", "bigpicture",
+ "--picture", bigPicture,
+ aTag, aText);
+ final Notification captured = captureNotification(aTag);
+ assertSame(captured.getNotificationStyle(), Notification.BigPictureStyle.class);
+ final Object pic = captured.extras.get(Notification.EXTRA_PICTURE);
+ assertThat(pic, instanceOf(Bitmap.class));
+ }
+
+ @Test
+ public void testInbox() throws Exception {
+ final int n = 25;
+ final String aTag = "inboxTag";
+ final String aText = "inboxText";
+ ArrayList<String> args = new ArrayList<>();
+ args.add("notify");
+ args.add("--style");
+ args.add("inbox");
+ final int startOfLineArgs = args.size();
+ for (int i = 0; i < n; i++) {
+ args.add("--line");
+ args.add(String.format("Line %02d", i));
+ }
+ args.add(aTag);
+ args.add(aText);
+
+ doCmd(args.toArray(new String[0]));
+ final Notification captured = captureNotification(aTag);
+ assertSame(captured.getNotificationStyle(), Notification.InboxStyle.class);
+ final Notification.Builder builder =
+ Notification.Builder.recoverBuilder(mContext, captured);
+ final ArrayList<CharSequence> lines =
+ ((Notification.InboxStyle) (builder.getStyle())).getLines();
+ for (int i = 0; i < n; i++) {
+ assertEquals(lines.get(i), args.get(1 + 2 * i + startOfLineArgs));
+ }
+ }
+
+ static final String[] PEOPLE = {
+ "Alice",
+ "Bob",
+ "Charlotte"
+ };
+ static final String[] MESSAGES = {
+ "Shall I compare thee to a summer's day?",
+ "Thou art more lovely and more temperate:",
+ "Rough winds do shake the darling buds of May,",
+ "And summer's lease hath all too short a date;",
+ "Sometime too hot the eye of heaven shines,",
+ "And often is his gold complexion dimm'd;",
+ "And every fair from fair sometime declines,",
+ "By chance or nature's changing course untrimm'd;",
+ "But thy eternal summer shall not fade,",
+ "Nor lose possession of that fair thou ow'st;",
+ "Nor shall death brag thou wander'st in his shade,",
+ "When in eternal lines to time thou grow'st:",
+ " So long as men can breathe or eyes can see,",
+ " So long lives this, and this gives life to thee.",
+ };
+
+ @Test
+ public void testMessaging() throws Exception {
+ final String aTag = "messagingTag";
+ final String aText = "messagingText";
+ ArrayList<String> args = new ArrayList<>();
+ args.add("notify");
+ args.add("--style");
+ args.add("messaging");
+ args.add("--conversation");
+ args.add("Sonnet 18");
+ final int startOfLineArgs = args.size();
+ for (int i = 0; i < MESSAGES.length; i++) {
+ args.add("--message");
+ args.add(String.format("%s:%s",
+ PEOPLE[i % PEOPLE.length],
+ MESSAGES[i % MESSAGES.length]));
+ }
+ args.add(aTag);
+ args.add(aText);
+
+ doCmd(args.toArray(new String[0]));
+ final Notification captured = captureNotification(aTag);
+ assertSame(Notification.MessagingStyle.class, captured.getNotificationStyle());
+ final Notification.Builder builder =
+ Notification.Builder.recoverBuilder(mContext, captured);
+ final Notification.MessagingStyle messagingStyle =
+ (Notification.MessagingStyle) (builder.getStyle());
+
+ assertEquals("Sonnet 18", messagingStyle.getConversationTitle());
+ final List<Notification.MessagingStyle.Message> messages = messagingStyle.getMessages();
+ for (int i = 0; i < messages.size(); i++) {
+ final Notification.MessagingStyle.Message m = messages.get(i);
+ assertEquals(MESSAGES[i], m.getText());
+ assertEquals(PEOPLE[i % PEOPLE.length], m.getSenderPerson().getName());
+ }
+
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index dc057d564a84..b315e514d6a6 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -101,4 +101,34 @@ public class SlicePermissionManagerTest extends UiServiceTestCase {
assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
}
-} \ No newline at end of file
+ @Test
+ public void testInvalid() throws Exception {
+ File sliceDir = new File(mContext.getCacheDir(), "slices-test");
+ if (!sliceDir.exists()) {
+ sliceDir.mkdir();
+ }
+ SlicePermissionManager permissions = new SlicePermissionManager(mContext,
+ TestableLooper.get(this).getLooper(), sliceDir);
+
+ DirtyTracker.Persistable junk = new DirtyTracker.Persistable() {
+ @Override
+ public String getFileName() {
+ return "invalidData";
+ }
+
+ @Override
+ public void writeTo(XmlSerializer out) throws IOException {
+ throw new RuntimeException("this doesn't work");
+ }
+ };
+
+ // let's put something bad in here
+ permissions.addDirtyImmediate(junk);
+ // force a persist. if this throws, it would take down system_server
+ permissions.handlePersist();
+
+ // Cleanup.
+ assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 61e968d6da00..7a6b2b50d1e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -565,7 +565,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
}
/**
@@ -580,7 +580,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
"disallowed_unsupportedUsecase_aborted", true,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
}
/**
@@ -595,47 +595,53 @@ public class ActivityStarterTests extends ActivityTestsBase {
runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callingUidHasVisibleWindow_notAborted", false,
UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callingUidProcessStateTop_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_realCallingUidHasVisibleWindow_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_realCallingUidProcessStateTop_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
- false, false);
+ false, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_hasForegroundActivities_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- true, false);
+ true, false, false);
runAndVerifyBackgroundActivityStartsSubtest(
"disallowed_callerIsRecents_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
- false, true);
+ false, true, false);
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "disallowed_callerIsWhitelisted_notAborted", false,
+ UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+ UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+ false, false, true);
}
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
- boolean hasForegroundActivities, boolean callerIsRecents) {
+ boolean hasForegroundActivities, boolean callerIsRecents,
+ boolean callerIsTempWhitelisted) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
callingUid);
@@ -656,6 +662,8 @@ public class ActivityStarterTests extends ActivityTestsBase {
RecentTasks recentTasks = mock(RecentTasks.class);
mService.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
+ // caller is temp whitelisted
+ callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 8e881b54c422..992d01766344 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -22,10 +22,10 @@ import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -43,11 +43,13 @@ import android.view.Surface;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.policy.WindowManagerPolicy;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.MockitoSession;
import java.io.File;
@@ -94,6 +96,12 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@After
public void tearDown() {
deleteRecursively(TEST_FOLDER);
+
+ // TODO(b/121296525): We may want to restore other display settings (not only overscans in
+ // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
+ // values after each test finishes, since we are going to reuse a singleton
+ // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
+ // (b/113239988).
}
@Test
@@ -245,21 +253,35 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testPersistOverscanInSameInstance() {
final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
- mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+ try {
+ mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */,
+ 4 /* bottom */);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
- assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+ assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */,
+ 4 /* bottom */);
+ } finally {
+ mTarget.setOverscanLocked(info, 0, 0, 0, 0);
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ }
}
@Test
public void testPersistOverscanAcrossInstances() {
final DisplayInfo info = mPrimaryDisplay.getDisplayInfo();
- mTarget.setOverscanLocked(info, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+ try {
+ mTarget.setOverscanLocked(info, 10 /* left */, 20 /* top */, 30 /* right */,
+ 40 /* bottom */);
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+ applySettingsToDisplayByNewInstance(mPrimaryDisplay);
- assertOverscan(mPrimaryDisplay, 1 /* left */, 2 /* top */, 3 /* right */, 4 /* bottom */);
+ assertOverscan(mPrimaryDisplay, 10 /* left */, 20 /* top */, 30 /* right */,
+ 40 /* bottom */);
+ } finally {
+ mTarget.setOverscanLocked(info, 0, 0, 0, 0);
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ }
}
@Test
@@ -389,26 +411,32 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
Surface.ROTATION_0);
+ final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .startMocking();
final DisplayRotation displayRotation = mock(DisplayRotation.class);
- mPrimaryDisplay = spy(mPrimaryDisplay);
- when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation);
+ spyOn(mPrimaryDisplay);
+ doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(false));
+ mockitoSession.finishMocking();
}
@Test
public void testSetFixedToUserRotation() {
mTarget.setFixedToUserRotation(mPrimaryDisplay, true);
+ final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .startMocking();
final DisplayRotation displayRotation = mock(DisplayRotation.class);
- mPrimaryDisplay = spy(mPrimaryDisplay);
- when(mPrimaryDisplay.getDisplayRotation()).thenReturn(displayRotation);
+ spyOn(mPrimaryDisplay);
+ doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
applySettingsToDisplayByNewInstance(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(true));
+ mockitoSession.finishMocking();
}
private static void assertOverscan(DisplayContent display, int left, int top, int right,
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 8821544903c1..374078625f4a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -19,13 +19,19 @@ package com.android.server.wm;
import static android.view.InsetsState.TYPE_TOP_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
+import android.view.InsetsState;
+import org.junit.Before;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -81,4 +87,41 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
mProvider.onPostLayout();
assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame());
}
+
+ @Test
+ public void testUpdateControlForTarget() {
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
+ topBar.getFrameLw().set(0, 0, 500, 100);
+ mProvider.setWindow(topBar, null);
+ mProvider.updateControlForTarget(target);
+ assertNotNull(mProvider.getControl());
+ mProvider.updateControlForTarget(null);
+ assertNull(mProvider.getControl());
+ }
+
+ @Test
+ public void testInsetsModified() {
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
+ topBar.getFrameLw().set(0, 0, 500, 100);
+ mProvider.setWindow(topBar, null);
+ mProvider.updateControlForTarget(target);
+ InsetsState state = new InsetsState();
+ state.getSource(TYPE_TOP_BAR).setVisible(false);
+ mProvider.onInsetsModified(target, state.getSource(TYPE_TOP_BAR));
+ assertFalse(mSource.isVisible());
+ }
+
+ @Test
+ public void testInsetsModified_noControl() {
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
+ topBar.getFrameLw().set(0, 0, 500, 100);
+ mProvider.setWindow(topBar, null);
+ InsetsState state = new InsetsState();
+ state.getSource(TYPE_TOP_BAR).setVisible(false);
+ mProvider.onInsetsModified(target, state.getSource(TYPE_TOP_BAR));
+ assertTrue(mSource.isVisible());
+ }
}
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 7186e22cefef..53e99fae95d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -199,6 +199,25 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
+ @Test
+ public void testUsesNoDisplaySourceHandoverDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = fullscreenDisplay.mDisplayId;
+ ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
+ ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.mHandoverLaunchDisplayId = freeformDisplay.mDisplayId;
+ source.noDisplay = true;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+ null /* layout */, mActivity, source, null /* options */, mCurrent, mResult));
+
+ assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
+ }
+
// =====================================
// Launch Windowing Mode Related Tests
// =====================================
@@ -768,6 +787,21 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
}
@Test
+ public void testReturnBoundsForFullscreenWindowingMode() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
+ }
+
+ @Test
public void testUsesDisplayOrientationForNoSensorOrientation() {
final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 6b6b33c52d91..7da85af444d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -34,6 +34,7 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -180,6 +181,24 @@ public class TaskRecordTests extends ActivityTestsBase {
mParentBounds);
}
+ /** Ensures that the alias intent won't have target component resolved. */
+ @Test
+ public void testTaskIntentActivityAlias() {
+ final String aliasActivity = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity";
+ final String targetActivity = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity";
+ final Intent intent = new Intent();
+ intent.setComponent(new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasActivity));
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
+ info.targetActivity = targetActivity;
+
+ final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
+ null /* taskDescription */);
+ assertEquals("The alias activity component should be saved in task intent.", aliasActivity,
+ task.intent.getComponent().getClassName());
+ }
+
private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
Rect expectedConfigBounds) {
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 7f7803463543..c09cd46a6c04 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
+import static android.view.InsetsState.TYPE_TOP_BAR;
import static android.view.Surface.ROTATION_0;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -31,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVE
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -56,6 +58,7 @@ import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.Size;
import android.view.DisplayCutout;
+import android.view.InsetsSource;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -326,6 +329,20 @@ public class WindowStateTests extends WindowTestsBase {
}
@Test
+ public void testVisibleWithInsetsProvider() throws Exception {
+ final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ topBar.mHasSurface = true;
+ assertTrue(topBar.isVisible());
+ mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
+ .setWindow(topBar, null);
+ mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(app);
+ mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
+ .onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR));
+ assertFalse(topBar.isVisible());
+ }
+
+ @Test
public void testIsSelfOrAncestorWindowAnimating() {
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 294b7509698b..f1e22819f501 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1744,8 +1744,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
USB_GADGET_HAL_DEATH_COOKIE);
mCurrentFunctions = UsbManager.FUNCTION_NONE;
- mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
mCurrentUsbFunctionsRequested = true;
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
}
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
index 5d675b76b395..700607536890 100644
--- a/startop/view_compiler/TEST_MAPPING
+++ b/startop/view_compiler/TEST_MAPPING
@@ -2,6 +2,10 @@
"presubmit": [
{
"name": "dex-builder-test"
+ },
+ {
+ "name": "view-compiler-tests",
+ "host": true
}
]
}
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 55bfdc78ec1b..609bcf377b46 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -32,6 +32,7 @@
namespace {
using namespace tinyxml2;
+using namespace startop::util;
using std::string;
constexpr char kStdoutFilename[]{"stdout"};
diff --git a/startop/view_compiler/util.cc b/startop/view_compiler/util.cc
index 69df41dff3d7..a0637e6da32f 100644
--- a/startop/view_compiler/util.cc
+++ b/startop/view_compiler/util.cc
@@ -18,6 +18,9 @@
using std::string;
+namespace startop {
+namespace util {
+
// TODO: see if we can borrow this from somewhere else, like aapt2.
string FindLayoutNameFromFilename(const string& filename) {
size_t start = filename.rfind("/");
@@ -30,3 +33,6 @@ string FindLayoutNameFromFilename(const string& filename) {
return filename.substr(start, end - start);
}
+
+} // namespace util
+} // namespace startop
diff --git a/startop/view_compiler/util.h b/startop/view_compiler/util.h
index 03e093920bfa..0176175920c1 100644
--- a/startop/view_compiler/util.h
+++ b/startop/view_compiler/util.h
@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef UTIL_H_
-#define UTIL_H_
+#ifndef VIEW_COMPILER_UTIL_H_
+#define VIEW_COMPILER_UTIL_H_
#include <string>
+namespace startop {
+namespace util {
+
std::string FindLayoutNameFromFilename(const std::string& filename);
-#endif // UTIL_H_
+} // namespace util
+} // namespace startop
+
+#endif // VIEW_COMPILER_UTIL_H_
diff --git a/startop/view_compiler/util_test.cc b/startop/view_compiler/util_test.cc
index d1540d3a6e43..50682a04e3b1 100644
--- a/startop/view_compiler/util_test.cc
+++ b/startop/view_compiler/util_test.cc
@@ -20,9 +20,15 @@
using std::string;
+namespace startop {
+namespace util {
+
TEST(UtilTest, FindLayoutNameFromFilename) {
- EXPECT_EQ("bar", ::FindLayoutNameFromFilename("foo/bar.xml"));
- EXPECT_EQ("bar", ::FindLayoutNameFromFilename("bar.xml"));
- EXPECT_EQ("bar", ::FindLayoutNameFromFilename("./foo/bar.xml"));
- EXPECT_EQ("bar", ::FindLayoutNameFromFilename("/foo/bar.xml"));
+ EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("foo/bar.xml"));
+ EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("bar.xml"));
+ EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("./foo/bar.xml"));
+ EXPECT_EQ("bar", startop::util::FindLayoutNameFromFilename("/foo/bar.xml"));
}
+
+} // namespace util
+} // namespace startop
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 0589cd4a538e..84256037b379 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -614,6 +614,11 @@ public abstract class Connection extends Conferenceable {
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
+ /**
+ * Connection extra key used to store SIP invite fields for an incoming call for IMS calls
+ */
+ public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
+
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 097e3529dead..5dedb045566c 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -168,7 +168,7 @@ public final class PhoneAccountHandle implements Parcelable {
}
};
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private PhoneAccountHandle(Parcel in) {
this(ComponentName.CREATOR.createFromParcel(in),
in.readString(),
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6e425dec0c34..312b31899ad6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1793,17 +1793,6 @@ public class CarrierConfigManager {
"editable_wfc_roaming_mode_bool";
/**
- * Determine whether current lpp_mode used for E-911 needs to be kept persistently.
- * {@code false} - not keeping the lpp_mode means using default configuration of gps.conf
- * when sim is not presented.
- * {@code true} - current lpp_profile of carrier will be kepted persistently
- * even after sim is removed.
- *
- * @hide
- */
- public static final String KEY_PERSIST_LPP_MODE_BOOL = "persist_lpp_mode_bool";
-
- /**
* Carrier specified WiFi networks.
* @hide
*/
@@ -2242,7 +2231,7 @@ public class CarrierConfigManager {
* e.g.) To use RSCP by default, set the value to "rscp". The signal strength level will
* then be determined by #KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY
* <p>
- * Currently this only supports the value "rscp"
+ * Currently this supports the value "rscp" and "rssi".
* @hide
*/
// FIXME: this key and related keys must not be exposed without a consistent philosophy for
@@ -2432,6 +2421,114 @@ public class CarrierConfigManager {
public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT =
"opportunistic_network_exit_threshold_rssnr_int";
+ /**
+ * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
+ * @hide
+ */
+ public static final class Gps {
+ /** Prefix of all Gps.KEY_* constants. */
+ public static final String KEY_PREFIX = "gps.";
+
+ /**
+ * Determine whether current lpp_mode used for E-911 needs to be kept persistently.
+ * {@code false} - not keeping the lpp_mode means using default configuration of gps.conf
+ * when sim is not presented.
+ * {@code true} - current lpp_profile of carrier will be kepted persistently
+ * even after sim is removed. This is default.
+ */
+ public static final String KEY_PERSIST_LPP_MODE_BOOL = KEY_PREFIX + "persist_lpp_mode_bool";
+
+ /**
+ * SUPL server host for SET Initiated & non-ES Network-Initiated SUPL requests.
+ * Default to supl.google.com
+ */
+ public static final String KEY_SUPL_HOST_STRING = KEY_PREFIX + "supl_host";
+
+ /** SUPL server port. Default to 7275. */
+ public static final String KEY_SUPL_PORT_STRING = KEY_PREFIX + "supl_port";
+
+ /**
+ * The SUPL version requested by Carrier. This is a bit mask
+ * with bits 0:7 representing a service indicator field, bits 8:15
+ * representing the minor version and bits 16:23 representing the
+ * major version. Default to 0x20000.
+ */
+ public static final String KEY_SUPL_VER_STRING = KEY_PREFIX + "supl_ver";
+
+ /**
+ * SUPL_MODE configuration bit mask
+ * 1 - Mobile Station Based. This is default.
+ * 2 - Mobile Station Assisted.
+ */
+ public static final String KEY_SUPL_MODE_STRING = KEY_PREFIX + "supl_mode";
+
+ /**
+ * Whether to limit responses to SUPL ES mode requests only during user emergency sessions
+ * (e.g. E911), and SUPL non-ES requests to only outside of non user emergency sessions.
+ * 0 - no.
+ * 1 - yes. This is default.
+ */
+ // TODO(b/119567985): name this key properly
+ public static final String KEY_SUPL_ES_STRING = KEY_PREFIX + "supl_es";
+
+ /**
+ * LTE Positioning Profile settings bit mask.
+ * 0 - Radio Resource Location Protocol in user plane and control plane. This is default.
+ * 1 - Enable LTE Positioning Protocol in user plane.
+ * 2 - Enable LTE Positioning Protocol in control plane.
+ */
+ public static final String KEY_LPP_PROFILE_STRING = KEY_PREFIX + "lpp_profile";
+
+ /**
+ * Determine whether to use emergency PDN for emergency SUPL.
+ * 0 - no.
+ * 1 - yes. This is default.
+ */
+ public static final String KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING =
+ KEY_PREFIX + "use_emergency_pdn_for_emergency_supl";
+
+ /**
+ * A_GLONASS_POS_PROTOCOL_SELECT bit mask.
+ * 0 - Don't use A-GLONASS. This is default.
+ * 1 - Use A-GLONASS in Radio Resource Control(RRC) control-plane.
+ * 2 - Use A-GLONASS in Radio Resource Location user-plane.
+ * 4 - Use A-GLONASS in LTE Positioning Protocol User plane.
+ */
+ public static final String KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING =
+ KEY_PREFIX + "a_glonass_pos_protocol_select";
+
+ /**
+ * GPS_LOCK configuration bit mask to specify GPS device behavior toward other services,
+ * when Location Settings are off.
+ * "0" - No lock.
+ * "1" - Lock Mobile Originated GPS functionalities.
+ * "2" - Lock Network initiated GPS functionalities.
+ * "3" - Lock both. This is default.
+ */
+ public static final String KEY_GPS_LOCK_STRING = KEY_PREFIX + "gps_lock";
+
+ /**
+ * SUPL NI emergency extension time in seconds. Default to "0".
+ */
+ public static final String KEY_ES_EXTENSION_SEC = KEY_PREFIX + "es_extension_sec";
+
+ private static PersistableBundle getDefaults() {
+ PersistableBundle defaults = new PersistableBundle();
+ defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
+ defaults.putString(KEY_SUPL_HOST_STRING, "supl.google.com");
+ defaults.putString(KEY_SUPL_PORT_STRING, "7275");
+ defaults.putString(KEY_SUPL_VER_STRING, "0x20000");
+ defaults.putString(KEY_SUPL_MODE_STRING, "1");
+ defaults.putString(KEY_SUPL_ES_STRING, "1");
+ defaults.putString(KEY_LPP_PROFILE_STRING, "0");
+ defaults.putString(KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING, "1");
+ defaults.putString(KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, "0");
+ defaults.putString(KEY_GPS_LOCK_STRING, "3");
+ defaults.putString(KEY_ES_EXTENSION_SEC, "0");
+ return defaults;
+ }
+ }
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -2724,7 +2821,6 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
- sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
@@ -2779,7 +2875,7 @@ public class CarrierConfigManager {
-95, /* SIGNAL_STRENGTH_GOOD */
-85 /* SIGNAL_STRENGTH_GREAT */
});
- sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
+ sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
sDefaults.putBoolean(KEY_CALL_FORWARDING_OVER_UT_WARNING_BOOL, false);
@@ -2801,6 +2897,7 @@ public class CarrierConfigManager {
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
/* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
+ sDefaults.putAll(Gps.getDefaults());
}
/**
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index d957d077e016..51393b90e61e 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -18,6 +18,7 @@ package android.telephony;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
@@ -65,7 +66,7 @@ public final class CellIdentityLte extends CellIdentity {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) {
this(ci, pci, tac, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, String.valueOf(mcc),
String.valueOf(mnc), null, null);
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 8c76eae0b544..c9f07dab6bbd 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Rlog;
@@ -41,7 +42,7 @@ public final class CellInfoCdma extends CellInfo implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public CellInfoCdma(CellInfoCdma ci) {
super(ci);
this.mCellIdentityCdma = ci.mCellIdentityCdma.copy();
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 8ca6a1a6815b..75938317bf44 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -75,7 +76,7 @@ public final class CellInfoLte extends CellInfo implements Parcelable {
return mCellIdentityLte;
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCellIdentity(CellIdentityLte cid) {
if (DBG) log("setCellIdentity: " + cid);
mCellIdentityLte = cid;
@@ -87,7 +88,7 @@ public final class CellInfoLte extends CellInfo implements Parcelable {
return mCellSignalStrengthLte;
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCellSignalStrength(CellSignalStrengthLte css) {
if (DBG) log("setCellSignalStrength: " + css);
mCellSignalStrengthLte = css;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index f2c14a147230..e6182eda852a 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -42,6 +42,9 @@ public abstract class CellSignalStrength {
public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
/** @hide */
+ protected static final int NUM_SIGNAL_STRENGTH_THRESHOLDS = NUM_SIGNAL_STRENGTH_BINS - 1;
+
+ /** @hide */
public static final String[] SIGNAL_STRENGTH_NAMES = {
"none", "poor", "moderate", "good", "great"
};
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 88f6fbc4464d..0760407171ae 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -21,6 +21,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.telephony.Rlog;
+import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -41,8 +42,18 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
private static final int WCDMA_RSSI_POOR = -107;
private static final int WCDMA_RSSI_MIN = -113;
- private static final int WCDMA_RSCP_MIN = -120;
+ private static final int[] sRssiThresholds = new int[]{
+ WCDMA_RSSI_POOR, WCDMA_RSSI_MODERATE, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT};
+
private static final int WCDMA_RSCP_MAX = -24;
+ private static final int WCDMA_RSCP_GREAT = -85;
+ private static final int WCDMA_RSCP_GOOD = -95;
+ private static final int WCDMA_RSCP_MODERATE = -105;
+ private static final int WCDMA_RSCP_POOR = -115;
+ private static final int WCDMA_RSCP_MIN = -120;
+
+ private static final int[] sRscpThresholds = new int[] {
+ WCDMA_RSCP_POOR, WCDMA_RSCP_MODERATE, WCDMA_RSCP_GOOD, WCDMA_RSCP_GREAT};
// TODO: Because these are used as values in CarrierConfig, they should be exposed somehow.
/** @hide */
@@ -54,6 +65,9 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
/** @hide */
public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
+ // Default to RSSI for backwards compatibility with older devices
+ private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+
private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
// CellInfo.UNAVAILABLE if unknown
@@ -121,10 +135,6 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
- private static final int[] sThresholds = new int[]{
- WCDMA_RSSI_POOR, WCDMA_RSSI_GOOD, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT};
-
/**
* Retrieve an abstract level value for the overall signal strength.
*
@@ -140,41 +150,46 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
String calcMethod;
- int[] thresholds;
+ int[] rscpThresholds;
if (cc == null) {
calcMethod = sLevelCalculationMethod;
- thresholds = sThresholds;
+ rscpThresholds = sRscpThresholds;
} else {
// TODO: abstract this entire thing into a series of functions
calcMethod = cc.getString(
CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
sLevelCalculationMethod);
- thresholds = cc.getIntArray(
+ if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod;
+ rscpThresholds = cc.getIntArray(
CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
- if (thresholds == null) thresholds = sThresholds;
+ if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
+ rscpThresholds = sRscpThresholds;
+ }
}
- int level = thresholds.length;
+ int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
switch (calcMethod) {
case LEVEL_CALCULATION_METHOD_RSCP:
if (mRscp < WCDMA_RSCP_MIN || mRscp > WCDMA_RSCP_MAX) {
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
return;
}
- while (level > 0 && mRscp < thresholds[level - 1]) level--;
+ while (level > 0 && mRscp < rscpThresholds[level - 1]) level--;
mLevel = level;
return;
+ default:
+ loge("Invalid Level Calculation Method for CellSignalStrengthWcdma = "
+ + calcMethod);
+ /** fall through */
case LEVEL_CALCULATION_METHOD_RSSI:
if (mRssi < WCDMA_RSSI_MIN || mRssi > WCDMA_RSSI_MAX) {
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
return;
}
- while (level > 0 && mRssi < thresholds[level - 1]) level--;
+ while (level > 0 && mRssi < sRssiThresholds[level - 1]) level--;
mLevel = level;
return;
- default:
- mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
}
@@ -204,7 +219,7 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
}
/**
- * Get the signal strength as dBm
+ * Get the RSSI as dBm
*
* @hide
*/
@@ -214,12 +229,32 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
/**
* Get the RSCP as dBm
+ *
* @hide
*/
public int getRscp() {
return mRscp;
}
+ /**
+ * Get the Ec/No as dB
+ *
+ * @hide
+ */
+ public int getEcNo() {
+ return mEcNo;
+ }
+
+ /**
+ * Return the Bit Error Rate
+ *
+ * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE.
+ * @hide
+ */
+ public int getBitErrorRate() {
+ return mBitErrorRate;
+ }
+
@Override
public int hashCode() {
return Objects.hash(mRssi, mBitErrorRate, mRscp, mEcNo, mLevel);
@@ -304,9 +339,16 @@ public final class CellSignalStrengthWcdma extends CellSignalStrength implements
};
/**
- * log
+ * log warning
*/
private static void log(String s) {
Rlog.w(LOG_TAG, s);
}
+
+ /**
+ * log error
+ */
+ private static void loge(String s) {
+ Rlog.e(LOG_TAG, s);
+ }
}
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index ac38efb4d029..1c615aba8d61 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -25,6 +25,7 @@ import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS;
import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -53,29 +54,29 @@ public class NeighboringCellInfo implements Parcelable
* In GSM, mRssi is the Received RSSI;
* In UMTS, mRssi is the Level index of CPICH Received Signal Code Power
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mRssi;
/**
* CID in 16 bits format in GSM. Return UNKNOWN_CID in UMTS and CMDA.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCid;
/**
* LAC in 16 bits format in GSM. Return UNKNOWN_CID in UMTS and CMDA.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mLac;
/**
* Primary Scrambling Code in 9 bits format in UMTS
* Return UNKNOWN_CID in GSM and CMDA.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mPsc;
/**
* Radio network type, value is one of following
* TelephonyManager.NETWORK_TYPE_XXXXXX.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mNetworkType;
/**
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index b258f52d58ec..83738997a067 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -17,10 +17,11 @@
package android.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.net.LinkProperties;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.TelephonyManager;
-import android.net.LinkProperties;
+
+import java.util.Objects;
/**
* Contains precise data connection state.
@@ -32,7 +33,6 @@ import android.net.LinkProperties;
* <li>Network type of the connection.
* <li>APN type.
* <li>APN.
- * <li>Data connection change reason.
* <li>The properties of the network link.
* <li>Data connection fail cause.
* </ul>
@@ -45,7 +45,6 @@ public class PreciseDataConnectionState implements Parcelable {
private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private String mAPNType = "";
private String mAPN = "";
- private String mReason = "";
private LinkProperties mLinkProperties = null;
private String mFailCause = "";
@@ -55,14 +54,12 @@ public class PreciseDataConnectionState implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- public PreciseDataConnectionState(int state, int networkType,
- String apnType, String apn, String reason,
- LinkProperties linkProperties, String failCause) {
+ public PreciseDataConnectionState(int state, int networkType, String apnType, String apn,
+ LinkProperties linkProperties, String failCause) {
mState = state;
mNetworkType = networkType;
mAPNType = apnType;
mAPN = apn;
- mReason = reason;
mLinkProperties = linkProperties;
mFailCause = failCause;
}
@@ -83,7 +80,6 @@ public class PreciseDataConnectionState implements Parcelable {
mNetworkType = in.readInt();
mAPNType = in.readString();
mAPN = in.readString();
- mReason = in.readString();
mLinkProperties = (LinkProperties)in.readParcelable(null);
mFailCause = in.readString();
}
@@ -144,14 +140,6 @@ public class PreciseDataConnectionState implements Parcelable {
}
/**
- * Get data connection change reason.
- */
- @UnsupportedAppUsage
- public String getDataConnectionChangeReason() {
- return mReason;
- }
-
- /**
* Get the properties of the network link.
*/
@UnsupportedAppUsage
@@ -178,7 +166,6 @@ public class PreciseDataConnectionState implements Parcelable {
out.writeInt(mNetworkType);
out.writeString(mAPNType);
out.writeString(mAPN);
- out.writeString(mReason);
out.writeParcelable(mLinkProperties, flags);
out.writeString(mFailCause);
}
@@ -197,16 +184,7 @@ public class PreciseDataConnectionState implements Parcelable {
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + mState;
- result = prime * result + mNetworkType;
- result = prime * result + ((mAPNType == null) ? 0 : mAPNType.hashCode());
- result = prime * result + ((mAPN == null) ? 0 : mAPN.hashCode());
- result = prime * result + ((mReason == null) ? 0 : mReason.hashCode());
- result = prime * result + ((mLinkProperties == null) ? 0 : mLinkProperties.hashCode());
- result = prime * result + ((mFailCause == null) ? 0 : mFailCause.hashCode());
- return result;
+ return Objects.hash(mState, mNetworkType, mAPNType, mAPN, mLinkProperties, mFailCause);
}
@Override
@@ -252,13 +230,6 @@ public class PreciseDataConnectionState implements Parcelable {
if (mNetworkType != other.mNetworkType) {
return false;
}
- if (mReason == null) {
- if (other.mReason != null) {
- return false;
- }
- } else if (!mReason.equals(other.mReason)) {
- return false;
- }
if (mState != other.mState) {
return false;
}
@@ -273,7 +244,6 @@ public class PreciseDataConnectionState implements Parcelable {
sb.append(", Network type: " + mNetworkType);
sb.append(", APN type: " + mAPNType);
sb.append(", APN: " + mAPN);
- sb.append(", Change reason: " + mReason);
sb.append(", Link properties: " + mLinkProperties);
sb.append(", Fail cause: " + mFailCause);
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index c4b70ab69c85..0d94c4dd3686 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -272,7 +273,7 @@ public class RadioAccessFamily implements Parcelable {
return TelephonyManager.NETWORK_CLASS_UNKNOWN;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int getNetworkTypeFromRaf(int raf) {
raf = getAdjustedRaf(raf);
diff --git a/telephony/java/android/telephony/Rlog.java b/telephony/java/android/telephony/Rlog.java
index 5f2fa335135f..cdab2dc54dd2 100644
--- a/telephony/java/android/telephony/Rlog.java
+++ b/telephony/java/android/telephony/Rlog.java
@@ -65,7 +65,7 @@ public final class Rlog {
return Log.println_native(Log.LOG_ID_RADIO, Log.INFO, tag, msg);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int i(String tag, String msg, Throwable tr) {
return Log.println_native(Log.LOG_ID_RADIO, Log.INFO, tag,
msg + '\n' + Log.getStackTraceString(tr));
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 78f05168198f..9fc1b6f76e77 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -317,19 +317,19 @@ public class ServiceState implements Parcelable {
@RilRadioTechnology
private int mRilDataRadioTechnology;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mCssIndicator;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mNetworkId;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mSystemId;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaRoamingIndicator;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaDefaultRoamingIndicator;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaEriIconIndex;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaEriIconMode;
@UnsupportedAppUsage
@@ -1071,7 +1071,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setDataRegState(int state) {
mDataRegState = state;
if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
@@ -1101,7 +1101,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setVoiceRoamingType(@RoamingType int type) {
NetworkRegistrationState regState = getNetworkRegistrationState(
NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
@@ -1122,7 +1122,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setDataRoamingType(@RoamingType int type) {
NetworkRegistrationState regState = getNetworkRegistrationState(
NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
@@ -1139,7 +1139,7 @@ public class ServiceState implements Parcelable {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setEmergencyOnly(boolean emergencyOnly) {
mIsEmergencyOnly = emergencyOnly;
}
@@ -1147,7 +1147,7 @@ public class ServiceState implements Parcelable {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCdmaRoamingIndicator(int roaming) {
this.mCdmaRoamingIndicator = roaming;
}
@@ -1155,7 +1155,7 @@ public class ServiceState implements Parcelable {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCdmaDefaultRoamingIndicator (int roaming) {
this.mCdmaDefaultRoamingIndicator = roaming;
}
@@ -1163,7 +1163,7 @@ public class ServiceState implements Parcelable {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCdmaEriIconIndex(int index) {
this.mCdmaEriIconIndex = index;
}
@@ -1171,7 +1171,7 @@ public class ServiceState implements Parcelable {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCdmaEriIconMode(int mode) {
this.mCdmaEriIconMode = mode;
}
@@ -1232,7 +1232,7 @@ public class ServiceState implements Parcelable {
* @param b second obj
* @return true if two objects equal or both are null
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static boolean equalsHandlesNulls (Object a, Object b) {
return (a == null) ? (b == null) : a.equals (b);
}
@@ -1389,7 +1389,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCssIndicator(int css) {
this.mCssIndicator = (css != 0);
}
@@ -1569,7 +1569,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getCssIndicator() {
return this.mCssIndicator ? 1 : 0;
}
@@ -1629,7 +1629,7 @@ public class ServiceState implements Parcelable {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 1b37bad65d57..1378bb004696 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.BaseBundle;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -89,7 +90,7 @@ public final class SmsManager {
new ArrayMap<Integer, SmsManager>();
/** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mSubId;
/*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d8b430f0f083..8dfdb2f4a334 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -772,7 +772,6 @@ public class TelephonyManager {
* The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
* The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
* The {@link #EXTRA_DATA_APN} extra indicates the APN.
- * The {@link #EXTRA_DATA_CHANGE_REASON} extra indicates the connection change reason.
* The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
* The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
*
@@ -783,7 +782,6 @@ public class TelephonyManager {
* @see #EXTRA_DATA_NETWORK_TYPE
* @see #EXTRA_DATA_APN_TYPE
* @see #EXTRA_DATA_APN
- * @see #EXTRA_DATA_CHANGE_REASON
* @see #EXTRA_DATA_IFACE
* @see #EXTRA_DATA_FAILURE_CAUSE
* @hide
@@ -873,18 +871,6 @@ public class TelephonyManager {
/**
* The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
- * for an String representation of the change reason.
- *
- * <p class="note">
- * Retrieve with
- * {@link android.content.Intent#getStringExtra(String name)}.
- *
- * @hide
- */
- public static final String EXTRA_DATA_CHANGE_REASON = PhoneConstants.STATE_CHANGE_REASON_KEY;
-
- /**
- * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
* for an String representation of the data interface.
*
* <p class="note">
@@ -8079,7 +8065,7 @@ public class TelephonyManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setSimOperatorNameForPhone(int phoneId, String name) {
setTelephonyProperty(phoneId,
TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, name);
@@ -8100,7 +8086,7 @@ public class TelephonyManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setSimCountryIsoForPhone(int phoneId, String iso) {
setTelephonyProperty(phoneId,
TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
@@ -8121,7 +8107,7 @@ public class TelephonyManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setSimStateForPhone(int phoneId, String state) {
setTelephonyProperty(phoneId,
TelephonyProperties.PROPERTY_SIM_STATE, state);
@@ -8227,7 +8213,7 @@ public class TelephonyManager {
* @param version baseband version
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setBasebandVersionForPhone(int phoneId, String version) {
setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_BASEBAND_VERSION, version);
}
@@ -8293,7 +8279,7 @@ public class TelephonyManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setPhoneType(int phoneId, int type) {
if (SubscriptionManager.isValidPhoneId(phoneId)) {
TelephonyManager.setTelephonyProperty(phoneId,
@@ -8323,7 +8309,7 @@ public class TelephonyManager {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String getOtaSpNumberSchemaForPhone(int phoneId, String defaultValue) {
if (SubscriptionManager.isValidPhoneId(phoneId)) {
return TelephonyManager.getTelephonyProperty(phoneId,
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
index cf961d0be10c..d0b751981c28 100644
--- a/telephony/java/android/telephony/VoLteServiceState.java
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -80,7 +81,7 @@ public final class VoLteServiceState implements Parcelable {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public VoLteServiceState(int srvccState) {
initialize();
diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
index ee602c06f0f7..45b1e474b93d 100644
--- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java
+++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
@@ -17,6 +17,7 @@
package android.telephony.cdma;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Bundle;
import android.telephony.CellLocation;
@@ -24,7 +25,7 @@ import android.telephony.CellLocation;
* Represents the cell location on a CDMA phone.
*/
public class CdmaCellLocation extends CellLocation {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mBaseStationId = -1;
/**
@@ -38,7 +39,7 @@ public class CdmaCellLocation extends CellLocation {
* to 1296000, both values inclusive (corresponding to a range of -90
* to +90 degrees). Integer.MAX_VALUE is considered invalid value.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mBaseStationLatitude = INVALID_LAT_LONG;
/**
@@ -47,12 +48,12 @@ public class CdmaCellLocation extends CellLocation {
* to 2592000, both values inclusive (corresponding to a range of -180
* to +180 degrees). Integer.MAX_VALUE is considered invalid value.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mBaseStationLongitude = INVALID_LAT_LONG;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mSystemId = -1;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mNetworkId = -1;
/**
@@ -206,7 +207,7 @@ public class CdmaCellLocation extends CellLocation {
* @param b second obj
* @return true if two objects equal or both are null
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private static boolean equalsHandlesNulls(Object a, Object b) {
return (a == null) ? (b == null) : a.equals (b);
}
diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java
index 98ce33368ca6..d6780ce107c9 100644
--- a/telephony/java/android/telephony/gsm/GsmCellLocation.java
+++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java
@@ -17,6 +17,7 @@
package android.telephony.gsm;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Bundle;
import android.telephony.CellLocation;
@@ -92,7 +93,7 @@ public class GsmCellLocation extends CellLocation {
* Set the primary scrambling code.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setPsc(int psc) {
mPsc = psc;
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index a6c24bf4e18a..cb6fcd7b62c2 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -262,6 +262,8 @@ public final class ImsCallProfile implements Parcelable {
public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
public static final String EXTRA_IS_CALL_PULL = "CallPull";
+ public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS =
+ "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
/**
* Extra key which the RIL can use to indicate the radio technology used for a call.
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl b/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
new file mode 100644
index 000000000000..9fdc41d2bd5f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable Rcs1To1Thread;
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
new file mode 100644
index 000000000000..709b3aa0f804
--- /dev/null
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * Rcs1To1Thread represents a single RCS conversation thread with a total of two
+ * {@link RcsParticipant}s.
+ * @hide - TODO(sahinc) make this public
+ */
+public class Rcs1To1Thread extends RcsThread {
+ public Rcs1To1Thread(int threadId) {
+ super(threadId);
+ }
+
+ public static final Creator<Rcs1To1Thread> CREATOR = new Creator<Rcs1To1Thread>() {
+ @Override
+ public Rcs1To1Thread createFromParcel(Parcel in) {
+ return new Rcs1To1Thread(in);
+ }
+
+ @Override
+ public Rcs1To1Thread[] newArray(int size) {
+ return new Rcs1To1Thread[size];
+ }
+ };
+
+ protected Rcs1To1Thread(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(RCS_1_TO_1_TYPE);
+ super.writeToParcel(dest, flags);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl b/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
new file mode 100644
index 000000000000..eaf312877deb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsFileTransferPart;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
new file mode 100644
index 000000000000..39c58dd9c15b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a file transfer.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsFileTransferPart extends RcsPart {
+ public static final Creator<RcsFileTransferPart> CREATOR = new Creator<RcsFileTransferPart>() {
+ @Override
+ public RcsFileTransferPart createFromParcel(Parcel in) {
+ return new RcsFileTransferPart(in);
+ }
+
+ @Override
+ public RcsFileTransferPart[] newArray(int size) {
+ return new RcsFileTransferPart[size];
+ }
+ };
+
+ protected RcsFileTransferPart(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.aidl b/telephony/java/android/telephony/ims/RcsGroupThread.aidl
new file mode 100644
index 000000000000..c4ce5299e512
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsGroupThread;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
new file mode 100644
index 000000000000..d954b2d70ac3
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join
+ * or leave.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsGroupThread extends RcsThread {
+ public static final Creator<RcsGroupThread> CREATOR = new Creator<RcsGroupThread>() {
+ @Override
+ public RcsGroupThread createFromParcel(Parcel in) {
+ return new RcsGroupThread(in);
+ }
+
+ @Override
+ public RcsGroupThread[] newArray(int size) {
+ return new RcsGroupThread[size];
+ }
+ };
+
+ protected RcsGroupThread(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(RCS_GROUP_TYPE);
+ super.writeToParcel(dest, flags);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl b/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
new file mode 100644
index 000000000000..6552a82c9072
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsIncomingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
new file mode 100644
index 000000000000..f39e06db068a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * This is a single instance of a message received over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsIncomingMessage extends RcsMessage {
+ public static final Creator<RcsIncomingMessage> CREATOR = new Creator<RcsIncomingMessage>() {
+ @Override
+ public RcsIncomingMessage createFromParcel(Parcel in) {
+ return new RcsIncomingMessage(in);
+ }
+
+ @Override
+ public RcsIncomingMessage[] newArray(int size) {
+ return new RcsIncomingMessage[size];
+ }
+ };
+
+ protected RcsIncomingMessage(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.aidl b/telephony/java/android/telephony/ims/RcsLocationPart.aidl
new file mode 100644
index 000000000000..4fe5ca97a30d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsLocationPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsLocationPart;
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.java b/telephony/java/android/telephony/ims/RcsLocationPart.java
new file mode 100644
index 000000000000..19be4ceaf688
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsLocationPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a location
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsLocationPart extends RcsPart {
+ public static final Creator<RcsLocationPart> CREATOR = new Creator<RcsLocationPart>() {
+ @Override
+ public RcsLocationPart createFromParcel(Parcel in) {
+ return new RcsLocationPart(in);
+ }
+
+ @Override
+ public RcsLocationPart[] newArray(int size) {
+ return new RcsLocationPart[size];
+ }
+ };
+
+ protected RcsLocationPart(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsManager.aidl b/telephony/java/android/telephony/ims/RcsManager.aidl
new file mode 100644
index 000000000000..63bc71c5ee46
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsManager.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsManager;
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
index d50b516b8754..df108c88e3b0 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.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.
diff --git a/telephony/java/android/telephony/ims/RcsMessage.aidl b/telephony/java/android/telephony/ims/RcsMessage.aidl
new file mode 100644
index 000000000000..b32cd1208c40
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsMessage;
diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java
new file mode 100644
index 000000000000..d46685c4a572
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * This is a single instance of a message sent or received over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsMessage implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index c89c0bebb1a1..1bf6ffd81ca0 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.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,6 +16,8 @@
package android.telephony.ims;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
@@ -27,26 +29,93 @@ import android.telephony.ims.aidl.IRcs;
* @hide - TODO make this public
*/
public class RcsMessageStore {
- private static final String TAG = "RcsMessageStore";
- private static final boolean VDBG = false;
+ static final String TAG = "RcsMessageStore";
/**
- * Delete the RcsThread identified by the given threadId.
+ * Returns the first chunk of existing {@link RcsThread}s in the common storage.
+ * @param queryParameters Parameters to specify to return a subset of all RcsThreads.
+ * Passing a value of null will return all threads.
+ */
+ @WorkerThread
+ public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParameters queryParameters) {
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ return iRcs.getRcsThreads(queryParameters);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the next chunk of {@link RcsThread}s in the common storage.
+ * @param continuationToken A token to continue the query to get the next chunk. This is
+ * obtained through {@link RcsThreadQueryResult#nextChunkToken}.
+ */
+ @WorkerThread
+ public RcsThreadQueryResult getRcsThreads(RcsThreadQueryContinuationToken continuationToken) {
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ return iRcs.getRcsThreadsWithToken(continuationToken);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a new 1 to 1 thread with the given participant and persists it in the storage.
+ */
+ @WorkerThread
+ public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ return iRcs.createRcs1To1Thread(recipient);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcs1To1Thread", re);
+ }
+
+ return null;
+ }
+
+ /**
+ * Delete the {@link RcsThread} identified by the given threadId.
* @param threadId threadId of the thread to be deleted.
*/
+ @WorkerThread
public void deleteThread(int threadId) {
- if (VDBG) logd("deleteThread: threadId: " + threadId);
try {
IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
if (iRcs != null) {
iRcs.deleteThread(threadId);
}
} catch (RemoteException re) {
-
+ Rlog.e(TAG, "RcsMessageStore: Exception happened during deleteThread", re);
}
}
- private static void logd(String msg) {
- Rlog.d(TAG, msg);
+ /**
+ * Creates a new participant and persists it in the storage.
+ * @param canonicalAddress The defining address (e.g. phone number) of the participant.
+ */
+ public RcsParticipant createRcsParticipant(String canonicalAddress) {
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ return iRcs.createRcsParticipant(canonicalAddress);
+ }
+ } catch (RemoteException re) {
+ Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcsParticipant", re);
+ }
+
+ return null;
}
}
diff --git a/telephony/java/android/telephony/ims/RcsMultiMediaPart.java b/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
new file mode 100644
index 000000000000..d295fba365f0
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a media that is rendered on the screen
+ * (i.e. image, video etc)
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsMultiMediaPart extends RcsFileTransferPart {
+ public static final Creator<RcsMultiMediaPart> CREATOR = new Creator<RcsMultiMediaPart>() {
+ @Override
+ public RcsMultiMediaPart createFromParcel(Parcel in) {
+ return new RcsMultiMediaPart(in);
+ }
+
+ @Override
+ public RcsMultiMediaPart[] newArray(int size) {
+ return new RcsMultiMediaPart[size];
+ }
+ };
+
+ protected RcsMultiMediaPart(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl b/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
new file mode 100644
index 000000000000..5992d95c3b9c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsMultimediaPart;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl b/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
new file mode 100644
index 000000000000..6e0c80f3af81
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsOutgoingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
new file mode 100644
index 000000000000..bfb161133618
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * This is a single instance of a message sent over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsOutgoingMessage extends RcsMessage {
+ public static final Creator<RcsOutgoingMessage> CREATOR = new Creator<RcsOutgoingMessage>() {
+ @Override
+ public RcsOutgoingMessage createFromParcel(Parcel in) {
+ return new RcsOutgoingMessage(in);
+ }
+
+ @Override
+ public RcsOutgoingMessage[] newArray(int size) {
+ return new RcsOutgoingMessage[size];
+ }
+ };
+
+ protected RcsOutgoingMessage(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsPart.aidl b/telephony/java/android/telephony/ims/RcsPart.aidl
new file mode 100644
index 000000000000..8b8077d57676
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsPart;
diff --git a/telephony/java/android/telephony/ims/RcsPart.java b/telephony/java/android/telephony/ims/RcsPart.java
new file mode 100644
index 000000000000..da501738a0bf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsPart.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * A part of a composite {@link RcsMessage}.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsPart implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.aidl b/telephony/java/android/telephony/ims/RcsParticipant.aidl
new file mode 100644
index 000000000000..1c4436367e54
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipant.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipant;
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java
new file mode 100644
index 000000000000..70500aaa2e8b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsParticipant implements Parcelable {
+ /**
+ * Returns the row id of this participant.
+ *
+ * TODO(sahinc) implement
+ * @hide
+ */
+ public int getId() {
+ return 12345;
+ }
+
+ public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() {
+ @Override
+ public RcsParticipant createFromParcel(Parcel in) {
+ return new RcsParticipant(in);
+ }
+
+ @Override
+ public RcsParticipant[] newArray(int size) {
+ return new RcsParticipant[size];
+ }
+ };
+
+ protected RcsParticipant(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
new file mode 100644
index 000000000000..b9d819054527
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipantAliasChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
new file mode 100644
index 000000000000..b9ca5a86f84d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.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 android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsParticipant}'s alias was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsParticipantAliasChangedEvent extends RcsParticipantEvent {
+ public static final Creator<RcsParticipantAliasChangedEvent> CREATOR =
+ new Creator<RcsParticipantAliasChangedEvent>() {
+ @Override
+ public RcsParticipantAliasChangedEvent createFromParcel(Parcel in) {
+ return new RcsParticipantAliasChangedEvent(in);
+ }
+
+ @Override
+ public RcsParticipantAliasChangedEvent[] newArray(int size) {
+ return new RcsParticipantAliasChangedEvent[size];
+ }
+ };
+
+ protected RcsParticipantAliasChangedEvent(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
new file mode 100644
index 000000000000..c0a77897abd5
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipantEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.java b/telephony/java/android/telephony/ims/RcsParticipantEvent.java
new file mode 100644
index 000000000000..371b8b723d0a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * An event that is associated with an {@link RcsParticipant}
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsParticipantEvent implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.aidl b/telephony/java/android/telephony/ims/RcsTextPart.aidl
new file mode 100644
index 000000000000..4f9fe1fe26fe
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsTextPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsTextPart;
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.java b/telephony/java/android/telephony/ims/RcsTextPart.java
new file mode 100644
index 000000000000..2a72df17f32a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsTextPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a string
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsTextPart extends RcsPart {
+ public static final Creator<RcsTextPart> CREATOR = new Creator<RcsTextPart>() {
+ @Override
+ public RcsTextPart createFromParcel(Parcel in) {
+ return new RcsTextPart(in);
+ }
+
+ @Override
+ public RcsTextPart[] newArray(int size) {
+ return new RcsTextPart[size];
+ }
+ };
+
+ protected RcsTextPart(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThread.aidl b/telephony/java/android/telephony/ims/RcsThread.aidl
index 79d473266272..d9cf6dbc0ff0 100644
--- a/telephony/java/android/telephony/ims/RcsThread.aidl
+++ b/telephony/java/android/telephony/ims/RcsThread.aidl
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2018, The Android Open Source Project
+ * 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.
diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java
index b7f440d94583..c0a0d946d204 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.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.
@@ -18,51 +18,51 @@ package android.telephony.ims;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.ims.aidl.IRcs;
+import android.util.Log;
/**
* RcsThread represents a single RCS conversation thread. It holds messages that were sent and
- * received and events that occured on that thread.
+ * received and events that occurred on that thread.
* @hide - TODO(sahinc) make this public
*/
-public class RcsThread implements Parcelable {
+public abstract class RcsThread implements Parcelable {
+ // Since this is an abstract class that gets parcelled, the sub-classes need to write these
+ // magic values into the parcel so that we know which type to unparcel into.
+ protected static final int RCS_1_TO_1_TYPE = 998;
+ protected static final int RCS_GROUP_TYPE = 999;
+
+ protected int mThreadId;
+
+ protected RcsThread(int threadId) {
+ mThreadId = threadId;
+ }
+
+ protected RcsThread(Parcel in) {
+ mThreadId = in.readInt();
+ }
+
public static final Creator<RcsThread> CREATOR = new Creator<RcsThread>() {
@Override
public RcsThread createFromParcel(Parcel in) {
- return new RcsThread(in);
+ int type = in.readInt();
+
+ switch (type) {
+ case RCS_1_TO_1_TYPE:
+ return new Rcs1To1Thread(in);
+ case RCS_GROUP_TYPE:
+ return new RcsGroupThread(in);
+ default:
+ Log.e(RcsMessageStore.TAG, "Cannot unparcel RcsThread, wrong type: " + type);
+ }
+ return null;
}
@Override
public RcsThread[] newArray(int size) {
- return new RcsThread[size];
+ return new RcsThread[0];
}
};
- protected RcsThread(Parcel in) {
- }
-
- /**
- * Returns the number of messages in this RCS thread.
- *
- * @hide
- */
- public int getMessageCount() {
- try {
- IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
- if (iRcs != null) {
- // TODO(sahinc): substitute to the regular thread id once we have database
- // TODO(sahinc): connection in place
- return iRcs.getMessageCount(/* rcsThreadId= */ 123);
- }
- } catch (RemoteException re) {
- // TODO(sahinc): Log something meaningful
- }
- return 0;
- }
-
- /** Implement the Parcelable interface */
@Override
public int describeContents() {
return 0;
@@ -70,5 +70,6 @@ public class RcsThread implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mThreadId);
}
}
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadEvent.aidl
new file mode 100644
index 000000000000..4a40d8906bbb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.java b/telephony/java/android/telephony/ims/RcsThreadEvent.java
new file mode 100644
index 000000000000..e10baab9d8c5
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * An event that happened on an {@link RcsThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsThreadEvent implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
new file mode 100644
index 000000000000..82d985df4c6c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadIconChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java
new file mode 100644
index 000000000000..b308fef46435
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.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 android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s icon was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadIconChangedEvent extends RcsThreadEvent {
+ public static final Creator<RcsThreadIconChangedEvent> CREATOR =
+ new Creator<RcsThreadIconChangedEvent>() {
+ @Override
+ public RcsThreadIconChangedEvent createFromParcel(Parcel in) {
+ return new RcsThreadIconChangedEvent(in);
+ }
+
+ @Override
+ public RcsThreadIconChangedEvent[] newArray(int size) {
+ return new RcsThreadIconChangedEvent[size];
+ }
+ };
+
+ protected RcsThreadIconChangedEvent(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
new file mode 100644
index 000000000000..54a311d02958
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadNameChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java
new file mode 100644
index 000000000000..6f5cfdf3b4c4
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.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 android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s name was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadNameChangedEvent extends RcsThreadEvent {
+ public static final Creator<RcsThreadNameChangedEvent> CREATOR =
+ new Creator<RcsThreadNameChangedEvent>() {
+ @Override
+ public RcsThreadNameChangedEvent createFromParcel(Parcel in) {
+ return new RcsThreadNameChangedEvent(in);
+ }
+
+ @Override
+ public RcsThreadNameChangedEvent[] newArray(int size) {
+ return new RcsThreadNameChangedEvent[size];
+ }
+ };
+
+ protected RcsThreadNameChangedEvent(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
new file mode 100644
index 000000000000..047a42466ee7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadParticipantJoinedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java
new file mode 100644
index 000000000000..5c4073c430e7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.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 android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an RCS participant has joined an {@link RcsGroupThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadParticipantJoinedEvent extends RcsThreadEvent {
+ public static final Creator<RcsThreadParticipantJoinedEvent> CREATOR =
+ new Creator<RcsThreadParticipantJoinedEvent>() {
+ @Override
+ public RcsThreadParticipantJoinedEvent createFromParcel(Parcel in) {
+ return new RcsThreadParticipantJoinedEvent(in);
+ }
+
+ @Override
+ public RcsThreadParticipantJoinedEvent[] newArray(int size) {
+ return new RcsThreadParticipantJoinedEvent[size];
+ }
+ };
+
+ protected RcsThreadParticipantJoinedEvent(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
new file mode 100644
index 000000000000..52f9bbd3cd93
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadParticipantLeftEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java
new file mode 100644
index 000000000000..4bf86b90ebb7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.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 android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an RCS participant has left an {@link RcsGroupThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadParticipantLeftEvent extends RcsThreadEvent {
+ public static final Creator<RcsThreadParticipantLeftEvent> CREATOR =
+ new Creator<RcsThreadParticipantLeftEvent>() {
+ @Override
+ public RcsThreadParticipantLeftEvent createFromParcel(Parcel in) {
+ return new RcsThreadParticipantLeftEvent(in);
+ }
+
+ @Override
+ public RcsThreadParticipantLeftEvent[] newArray(int size) {
+ return new RcsThreadParticipantLeftEvent[size];
+ }
+ };
+
+ protected RcsThreadParticipantLeftEvent(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/packages/SystemUI/res/drawable/qs_tile_background.xml b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
index 96891c14bd33..7bcebfa08fcb 100644
--- a/packages/SystemUI/res/drawable/qs_tile_background.xml
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
@@ -1,7 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/*
-** Copyright 2012, The Android Open Source Project
+**
+** Copyright 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.
@@ -15,12 +14,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <color android:color="#212121" />
- </item>
- <item>
- <color android:color="#161616" />
- </item>
-</selector>
+
+package android.telephony.ims;
+
+parcelable RcsThreadQueryContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
new file mode 100644
index 000000000000..931e93dc8bf1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A continuation token to provide for {@link RcsMessageStore#getRcsThreads}. Use this token to
+ * break large queries into manageable chunks
+ * @hide - TODO make this public
+ */
+public class RcsThreadQueryContinuationToken implements Parcelable {
+ protected RcsThreadQueryContinuationToken(Parcel in) {
+ }
+
+ public static final Creator<RcsThreadQueryContinuationToken> CREATOR =
+ new Creator<RcsThreadQueryContinuationToken>() {
+ @Override
+ public RcsThreadQueryContinuationToken createFromParcel(Parcel in) {
+ return new RcsThreadQueryContinuationToken(in);
+ }
+
+ @Override
+ public RcsThreadQueryContinuationToken[] newArray(int size) {
+ return new RcsThreadQueryContinuationToken[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+}
diff --git a/packages/SystemUI/res/drawable/header_dot.xml b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
index dbc6b378bd63..feb2d4dec094 100644
--- a/packages/SystemUI/res/drawable/header_dot.xml
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2015, The Android Open Source Project
+/*
+**
+** Copyright 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.
@@ -13,16 +13,8 @@
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
--->
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval"
- android:tint="?android:attr/colorControlNormal">
+*/
- <solid
- android:color="#FFFFFF"/>
+package android.telephony.ims;
- <size
- android:width="3dp"
- android:height="3dp"/>
-</shape>
+parcelable RcsThreadQueryParameters;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
new file mode 100644
index 000000000000..f2c4ab1884ca
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)} in
+ * order to select a subset of {@link RcsThread}s present in the message store.
+ * @hide TODO - make the Builder and builder() public. The rest should stay internal only.
+ */
+public class RcsThreadQueryParameters implements Parcelable {
+ private final boolean mIsGroup;
+ private final Set<RcsParticipant> mRcsParticipants;
+ private final int mLimit;
+ private final boolean mIsAscending;
+
+ RcsThreadQueryParameters(boolean isGroup, Set<RcsParticipant> participants, int limit,
+ boolean isAscending) {
+ mIsGroup = isGroup;
+ mRcsParticipants = participants;
+ mLimit = limit;
+ mIsAscending = isAscending;
+ }
+
+ /**
+ * Returns a new builder to build a query with.
+ * TODO - make public
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+ * the list of participants.
+ * @hide
+ */
+ public Set<RcsParticipant> getRcsParticipants() {
+ return mRcsParticipants;
+ }
+
+ /**
+ * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+ * whether group threads should be queried
+ * @hide
+ */
+ public boolean isGroupThread() {
+ return mIsGroup;
+ }
+
+ /**
+ * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+ * the number of tuples the result query should be limited to.
+ */
+ public int getLimit() {
+ return mLimit;
+ }
+
+ /**
+ * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
+ * determine the sort order.
+ */
+ public boolean isAscending() {
+ return mIsAscending;
+ }
+
+ /**
+ * A helper class to build the {@link RcsThreadQueryParameters}.
+ */
+ public static class Builder {
+ private boolean mIsGroupThread;
+ private Set<RcsParticipant> mParticipants;
+ private int mLimit = 100;
+ private boolean mIsAscending;
+
+ /**
+ * Package private constructor for {@link RcsThreadQueryParameters.Builder}. To obtain this,
+ * {@link RcsThreadQueryParameters#builder()} needs to be called.
+ */
+ Builder() {
+ mParticipants = new HashSet<>();
+ }
+
+ /**
+ * Limits the query to only return group threads.
+ * @param isGroupThread Whether to limit the query result to group threads.
+ * @return The same instance of the builder to chain parameters.
+ */
+ @CheckResult
+ public Builder isGroupThread(boolean isGroupThread) {
+ mIsGroupThread = isGroupThread;
+ return this;
+ }
+
+ /**
+ * Limits the query to only return threads that contain the given participant.
+ * @param participant The participant that must be included in all of the returned threads.
+ * @return The same instance of the builder to chain parameters.
+ */
+ @CheckResult
+ public Builder withParticipant(RcsParticipant participant) {
+ mParticipants.add(participant);
+ return this;
+ }
+
+ /**
+ * Limits the query to only return threads that contain the given list of participants.
+ * @param participants An iterable list of participants that must be included in all of the
+ * returned threads.
+ * @return The same instance of the builder to chain parameters.
+ */
+ @CheckResult
+ public Builder withParticipants(Iterable<RcsParticipant> participants) {
+ for (RcsParticipant participant : participants) {
+ mParticipants.add(participant);
+ }
+ return this;
+ }
+
+ /**
+ * Desired number of threads to be returned from the query. Passing in 0 will return all
+ * existing threads at once. The limit defaults to 100.
+ * @param limit The number to limit the query result to.
+ * @return The same instance of the builder to chain parameters.
+ * @throws InvalidParameterException If the given limit is negative.
+ */
+ @CheckResult
+ public Builder limitResultsTo(int limit) throws InvalidParameterException {
+ if (limit < 0) {
+ throw new InvalidParameterException("The query limit must be non-negative");
+ }
+
+ mLimit = limit;
+ return this;
+ }
+
+ /**
+ * Sorts the results returned from the query via thread IDs.
+ *
+ * TODO - add sorting support for other fields
+ *
+ * @param isAscending whether to sort in ascending order or not
+ * @return The same instance of the builder to chain parameters.
+ */
+ @CheckResult
+ public Builder sort(boolean isAscending) {
+ mIsAscending = isAscending;
+ return this;
+ }
+
+ /**
+ * Builds the {@link RcsThreadQueryParameters} to use in
+ * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)}
+ *
+ * @return An instance of {@link RcsThreadQueryParameters} to use with the thread query.
+ */
+ public RcsThreadQueryParameters build() {
+ return new RcsThreadQueryParameters(
+ mIsGroupThread, mParticipants, mLimit, mIsAscending);
+ }
+ }
+
+ /**
+ * Parcelable boilerplate below.
+ */
+ protected RcsThreadQueryParameters(Parcel in) {
+ mIsGroup = in.readBoolean();
+
+ ArrayList<RcsParticipant> participantArrayList = new ArrayList<>();
+ in.readTypedList(participantArrayList, RcsParticipant.CREATOR);
+ mRcsParticipants = new HashSet<>(participantArrayList);
+
+ mLimit = in.readInt();
+ mIsAscending = in.readBoolean();
+ }
+
+ public static final Creator<RcsThreadQueryParameters> CREATOR =
+ new Creator<RcsThreadQueryParameters>() {
+ @Override
+ public RcsThreadQueryParameters createFromParcel(Parcel in) {
+ return new RcsThreadQueryParameters(in);
+ }
+
+ @Override
+ public RcsThreadQueryParameters[] newArray(int size) {
+ return new RcsThreadQueryParameters[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mIsGroup);
+ dest.writeTypedList(new ArrayList<>(mRcsParticipants));
+ dest.writeInt(mLimit);
+ dest.writeBoolean(mIsAscending);
+ }
+
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
new file mode 100644
index 000000000000..4b06529d1294
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony.ims;
+
+parcelable RcsThreadQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
new file mode 100644
index 000000000000..47715f8410d6
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken,
+ * RcsThreadQueryParameters)}
+ * call. This class allows getting the token for querying the next batch of threads in order to
+ * prevent handling large amounts of data at once.
+ *
+ * @hide
+ */
+public class RcsThreadQueryResult implements Parcelable {
+ private RcsThreadQueryContinuationToken mContinuationToken;
+ private List<RcsThread> mRcsThreads;
+
+ /**
+ * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+ * to create query results
+ *
+ * @hide
+ */
+ public RcsThreadQueryResult(
+ RcsThreadQueryContinuationToken continuationToken, List<RcsThread> rcsThreads) {
+ mContinuationToken = continuationToken;
+ mRcsThreads = rcsThreads;
+ }
+
+ /**
+ * Returns a token to call
+ * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)}
+ * to get the next batch of {@link RcsThread}s.
+ */
+ public RcsThreadQueryContinuationToken nextChunkToken() {
+ return mContinuationToken;
+ }
+
+ /**
+ * Returns all the RcsThreads in the current query result. Call {@link
+ * RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)} to get the next batch of
+ * {@link RcsThread}s.
+ */
+ public List<RcsThread> getThreads() {
+ return mRcsThreads;
+ }
+
+ protected RcsThreadQueryResult(Parcel in) {
+ // TODO - implement
+ }
+
+ public static final Creator<RcsThreadQueryResult> CREATOR =
+ new Creator<RcsThreadQueryResult>() {
+ @Override
+ public RcsThreadQueryResult createFromParcel(Parcel in) {
+ return new RcsThreadQueryResult(in);
+ }
+
+ @Override
+ public RcsThreadQueryResult[] newArray(int size) {
+ return new RcsThreadQueryResult[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // TODO - implement
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index b2e2fadca138..9badac5be230 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -16,14 +16,29 @@
package android.telephony.ims.aidl;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.Rcs1To1Thread;
+import android.telephony.ims.RcsThreadQueryContinuationToken;
+import android.telephony.ims.RcsThreadQueryParameters;
+import android.telephony.ims.RcsThreadQueryResult;
+
/**
* RPC definition between RCS storage APIs and phone process.
* {@hide}
*/
interface IRcs {
// RcsMessageStore APIs
+ RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParameters queryParameters);
+
+ RcsThreadQueryResult getRcsThreadsWithToken(
+ in RcsThreadQueryContinuationToken continuationToken);
+
void deleteThread(int threadId);
+ Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
+
+ RcsParticipant createRcsParticipant(String canonicalAddress);
+
// RcsThread APIs
int getMessageCount(int rcsThreadId);
} \ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 69ff329e2d07..84c0e6453104 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -21,6 +21,7 @@ import android.text.TextUtils;
import android.util.SparseIntArray;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.telephony.Rlog;
import java.nio.ByteBuffer;
@@ -587,7 +588,7 @@ public class GsmAlphabet {
* Additionally, in some country(ex. Korea), there are non-ASCII or MBCS characters.
* If a character set is given, characters in data are treat as MBCS.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static String
gsm8BitUnpackedToString(byte[] data, int offset, int length, String characterset) {
boolean isMbcs = false;
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index d9f5c3f6d0fa..02a6f311c1da 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -50,13 +50,13 @@ interface ITelephonyRegistry {
void notifyDataActivity(int state);
void notifyDataActivityForSubscriber(in int subId, int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, String apnType, in LinkProperties linkProperties,
+ String apn, String apnType, in LinkProperties linkProperties,
in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataConnectivityPossible,
- String reason, String apn, String apnType, in LinkProperties linkProperties,
+ String apn, String apnType, in LinkProperties linkProperties,
in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
- void notifyDataConnectionFailed(String reason, String apnType);
- void notifyDataConnectionFailedForSubscriber(int subId, String reason, String apnType);
+ void notifyDataConnectionFailed(String apnType);
+ void notifyDataConnectionFailedForSubscriber(int subId, String apnType);
void notifyCellLocation(in Bundle cellLocation);
void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
@@ -67,7 +67,7 @@ interface ITelephonyRegistry {
void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
int backgroundCallState);
void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
- void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
+ void notifyPreciseDataConnectionFailed(String apnType, String apn,
String failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
void notifySrvccStateChanged(in int subId, in int lteState);
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index a47e2b026021..59c39b158387 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -91,7 +92,7 @@ public class OperatorInfo implements Parcelable {
operatorNumeric, rilStateToState(stateString));
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public OperatorInfo(String operatorAlphaLong,
String operatorAlphaShort,
String operatorNumeric) {
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 21f3b92c6c4f..e87d28c6f9e9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -79,8 +79,6 @@ public class PhoneConstants {
public static final int SIM_ACTIVATION_TYPE_DATA = 1;
public static final String PHONE_NAME_KEY = "phoneName";
- public static final String FAILURE_REASON_KEY = "reason";
- public static final String STATE_CHANGE_REASON_KEY = "reason";
public static final String DATA_NETWORK_TYPE_KEY = "networkType";
public static final String DATA_FAILURE_CAUSE_KEY = "failCause";
public static final String DATA_APN_TYPE_KEY = "apnType";
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 7b1ead9722b8..190eac4d8c02 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -23,6 +23,7 @@ import java.text.BreakIterator;
import java.util.Arrays;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import android.text.Emoji;
@@ -118,7 +119,7 @@ public abstract class SmsMessageBase {
* Returns the address of the SMS service center that relayed this message
* or null if there is none.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public String getServiceCenterAddress() {
return mScAddress;
}
@@ -223,14 +224,14 @@ public abstract class SmsMessageBase {
/**
* Get protocol identifier.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public abstract int getProtocolIdentifier();
/**
* See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
* SMS
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public abstract boolean isReplace();
/**
@@ -302,7 +303,7 @@ public abstract class SmsMessageBase {
* See TS 23.040, 9.9.2.3.15 for a description of other possible
* values.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public abstract int getStatus();
/**
@@ -315,7 +316,7 @@ public abstract class SmsMessageBase {
* Returns true iff the <code>TP-Reply-Path</code> bit is set in
* this message.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public abstract boolean isReplyPathPresent();
/**
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index 0ac35bc2628c..e9a5ff70a7cc 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -119,7 +119,7 @@ public class MockContentProvider extends ContentProvider {
@Override
public IBinder asBinder() {
- throw new UnsupportedOperationException();
+ return MockContentProvider.this.getIContentProviderBinder();
}
@Override
@@ -279,6 +279,13 @@ public class MockContentProvider extends ContentProvider {
}
/**
+ * @hide
+ */
+ public IBinder getIContentProviderBinder() {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ /**
* Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
* when directly instantiating the provider for testing.
*
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 89734e35c13f..226c0b8c07d6 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -18,8 +18,6 @@ package android.test.mock;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -52,7 +50,6 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.Handler;
import android.os.PersistableBundle;
import android.os.UserHandle;
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
index 1548d6ed8a03..f7c60fc73cb3 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewActivity.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.ActivityView;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Parcelable;
import android.widget.Button;
public class ActivityViewActivity extends Activity {
@@ -41,6 +42,10 @@ public class ActivityViewActivity extends Activity {
final Intent intent = Intent.makeMainActivity(null);
final Intent chooser = Intent.createChooser(intent,
"Pick an app to launch in ActivityView");
+ chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] {
+ new Intent(Intent.ACTION_MAIN)
+ .addCategory("com.android.internal.category.PLATLOGO")
+ });
if (intent.resolveActivity(getPackageManager()) != null) {
chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
diff --git a/tests/RcsTests/Android.mk b/tests/RcsTests/Android.mk
index adc7cab91389..7b348d73747a 100644
--- a/tests/RcsTests/Android.mk
+++ b/tests/RcsTests/Android.mk
@@ -11,7 +11,7 @@ LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4 truth-prebuilt
include $(BUILD_PACKAGE)
diff --git a/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
index 290e04ce8abb..44277edcdb8c 100644
--- a/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tests.rcs;
+package com.android.tests.ims;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.ims.RcsMessageStore;
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
new file mode 100644
index 000000000000..a890a389bdfc
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsThreadQueryParameters;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsThreadQueryParametersTest {
+ private RcsThreadQueryParameters mRcsThreadQueryParameters;
+ @Mock RcsParticipant mMockParticipant;
+
+ @Test
+ public void testUnparceling() {
+ String key = "some key";
+ mRcsThreadQueryParameters = RcsThreadQueryParameters.builder()
+ .isGroupThread(true)
+ .withParticipant(mMockParticipant)
+ .limitResultsTo(50)
+ .sort(true)
+ .build();
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(key, mRcsThreadQueryParameters);
+ mRcsThreadQueryParameters = bundle.getParcelable(key);
+
+ assertThat(mRcsThreadQueryParameters.isGroupThread()).isTrue();
+ assertThat(mRcsThreadQueryParameters.getRcsParticipants()).contains(mMockParticipant);
+ assertThat(mRcsThreadQueryParameters.getLimit()).isEqualTo(50);
+ assertThat(mRcsThreadQueryParameters.isAscending()).isTrue();
+ }
+}
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
new file mode 100644
index 000000000000..34aa258bf465
--- /dev/null
+++ b/tests/RollbackTest/Android.mk
@@ -0,0 +1,81 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# RollbackTestAppAv1.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_PACKAGE_NAME := RollbackTestAppAv1
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_AV1 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTestAppAv2.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_PACKAGE_NAME := RollbackTestAppAv2
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTestAppBv1.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/Bv1.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppBv1
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_BV1 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTestAppBv2.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/Bv2.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppBv2
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_BV2 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := RollbackTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_JAVA_RESOURCE_FILES := \
+ $(ROLLBACK_TEST_APP_AV1) \
+ $(ROLLBACK_TEST_APP_AV2) \
+ $(ROLLBACK_TEST_APP_BV1) \
+ $(ROLLBACK_TEST_APP_BV2)
+LOCAL_SDK_VERSION := system_current
+LOCAL_TEST_CONFIG := RollbackTest.xml
+include $(BUILD_PACKAGE)
+
+# Clean up local variables
+ROLLBACK_TEST_APP_AV1 :=
+ROLLBACK_TEST_APP_AV2 :=
+ROLLBACK_TEST_APP_BV1 :=
+ROLLBACK_TEST_APP_BV2 :=
diff --git a/packages/SystemUI/res/drawable/tv_pip_outline.xml b/tests/RollbackTest/AndroidManifest.xml
index c84438c2e55e..e57a768ad1b5 100644
--- a/packages/SystemUI/res/drawable/tv_pip_outline.xml
+++ b/tests/RollbackTest/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- 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.
@@ -14,7 +14,18 @@
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <stroke android:width="2dp" android:color="#EEEEEE" />
-</shape>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.rollback" >
+
+ <application>
+ <receiver android:name="com.android.tests.rollback.LocalIntentSender"
+ android:exported="true" />
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.tests.rollback"
+ android:label="Rollback Test"/>
+
+</manifest>
diff --git a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml b/tests/RollbackTest/RollbackTest.xml
index 3a47261851a5..adbad56cd934 100644
--- a/packages/SystemUI/res/drawable/ic_notify_button_bg.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
+<!-- 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.
@@ -13,8 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@*android:drawable/list_selector_pressed_holo_dark" />
-</selector>
+<configuration description="Runs the rollback tests">
+ <option name="test-suite-tag" value="RollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="RollbackTest.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.tests.rollback" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml
new file mode 100644
index 000000000000..996d831013a8
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Av1.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.rollback.testapp.A"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+
+ <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">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml
new file mode 100644
index 000000000000..21c7260b570b
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Av2.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.rollback.testapp.A"
+ android:versionCode="2"
+ android:versionName="2.0" >
+
+
+ <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">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml
new file mode 100644
index 000000000000..de0fd0d6d616
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Bv1.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.rollback.testapp.B"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+
+ <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">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml
new file mode 100644
index 000000000000..6c2e66a3220c
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Bv2.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.rollback.testapp.B"
+ android:versionCode="2"
+ android:versionName="2.0" >
+
+
+ <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">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
new file mode 100644
index 000000000000..9f1a0609d3f1
--- /dev/null
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A test app for testing apk rollback support.
+ */
+public class MainActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ new ProcessUserData().processUserData(this);
+ } catch (ProcessUserData.UserDataException e) {
+ throw new AssertionError("Failed to process app user data", e);
+ }
+ }
+}
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
new file mode 100644
index 000000000000..fde6a83b6e56
--- /dev/null
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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 java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Scanner;
+
+/**
+ * A broadcast reciever to check for and update user app data version
+ * compatibility.
+ */
+public class ProcessUserData extends BroadcastReceiver {
+
+ /**
+ * Exception thrown in case of issue with user data.
+ */
+ public static class UserDataException extends Exception {
+ public UserDataException(String message) {
+ super(message);
+ }
+
+ public UserDataException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ processUserData(context);
+ setResultCode(1);
+ } catch (UserDataException e) {
+ setResultCode(0);
+ setResultData(e.getMessage());
+ }
+ }
+
+ /**
+ * Update the app's user data version to match the app version.
+ *
+ * @param context The application context.
+ * @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);
+ }
+
+ // Read the version of the app's user data and ensure it is compatible
+ // with our version of the application.
+ File versionFile = new File(context.getFilesDir(), "version.txt");
+ try {
+ Scanner s = new Scanner(versionFile);
+ int userDataVersion = s.nextInt();
+ s.close();
+
+ if (userDataVersion > appVersion) {
+ throw new UserDataException("User data is from version " + userDataVersion
+ + ", which is not compatible with this version " + appVersion
+ + " of the RollbackTestApp");
+ }
+ } catch (FileNotFoundException e) {
+ // No problem. This is a fresh install of the app or the user data
+ // has been wiped.
+ }
+
+ // Record the current version of the app in the user data.
+ try {
+ PrintWriter pw = new PrintWriter(versionFile);
+ pw.println(appVersion);
+ pw.close();
+ } catch (IOException e) {
+ throw new UserDataException("Unable to write user data.", e);
+ }
+ }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java b/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
new file mode 100644
index 000000000000..ddcf1dabcafc
--- /dev/null
+++ b/tests/RollbackTest/src/com/android/tests/rollback/LocalIntentSender.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.support.test.InstrumentationRegistry;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Make IntentSender that sends intent locally.
+ */
+public class LocalIntentSender extends BroadcastReceiver {
+
+ private static final String TAG = "RollbackTest";
+
+ private static final BlockingQueue<Intent> sIntentSenderResults = new LinkedBlockingQueue<>();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sIntentSenderResults.add(intent);
+ }
+
+ /**
+ * Get a LocalIntentSender.
+ */
+ static IntentSender getIntentSender() {
+ Context context = InstrumentationRegistry.getContext();
+ Intent intent = new Intent(context, LocalIntentSender.class);
+ PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, 0);
+ return pending.getIntentSender();
+ }
+
+ /**
+ * Returns the most recent Intent sent by a LocalIntentSender.
+ */
+ static Intent getIntentSenderResult() throws InterruptedException {
+ return sIntentSenderResults.take();
+ }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
new file mode 100644
index 000000000000..d3c39f0b8248
--- /dev/null
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A broadcast receiver that can be used to get
+ * ACTION_PACKAGE_ROLLBACK_EXECUTED broadcasts.
+ */
+class RollbackBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "RollbackTest";
+
+ private final BlockingQueue<Intent> mRollbackBroadcasts = new LinkedBlockingQueue<>();
+
+ /**
+ * Creates a RollbackBroadcastReceiver and registers it with the given
+ * context.
+ */
+ RollbackBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ filter.addDataScheme("package");
+ InstrumentationRegistry.getContext().registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "Received rollback broadcast intent");
+ mRollbackBroadcasts.add(intent);
+ }
+
+ /**
+ * Polls for at most the given amount of time for the next rollback
+ * broadcast.
+ */
+ Intent poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return mRollbackBroadcasts.poll(timeout, unit);
+ }
+
+ /**
+ * Unregisters this broadcast receiver.
+ */
+ void unregister() {
+ InstrumentationRegistry.getContext().unregisterReceiver(this);
+ }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
new file mode 100644
index 000000000000..0ccfb19d3f0b
--- /dev/null
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test system Rollback APIs.
+ * TODO: Should this be a cts test instead? Where should it live?
+ */
+@RunWith(JUnit4.class)
+public class RollbackTest {
+
+ private static final String TAG = "RollbackTest";
+
+ private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+ private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
+
+ /**
+ * Test basic rollbacks.
+ */
+ @Test
+ public void testBasic() throws Exception {
+ // Make sure an app can't listen to or disturb the internal
+ // ACTION_PACKAGE_ENABLE_ROLLBACK broadcast.
+ Context context = InstrumentationRegistry.getContext();
+ IntentFilter enableRollbackFilter = new IntentFilter();
+ enableRollbackFilter.addAction("android.intent.action.PACKAGE_ENABLE_ROLLBACK");
+ enableRollbackFilter.addDataType("application/vnd.android.package-archive");
+ enableRollbackFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ BroadcastReceiver enableRollbackReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ abortBroadcast();
+ }
+ };
+ context.registerReceiver(enableRollbackReceiver, enableRollbackFilter);
+
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ // Register a broadcast receiver for notification when the rollback is
+ // done executing.
+ RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ // Uninstall TEST_APP_A
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // TODO: There is currently a race condition between when the app is
+ // uninstalled and when rollback manager deletes the rollback. Fix it
+ // so that's not the case!
+ for (int i = 0; i < 5; ++i) {
+ for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+ if (TEST_APP_A.equals(info.targetPackage.packageName)) {
+ Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+ Thread.sleep(1000);
+ break;
+ }
+ }
+ }
+
+ // The app should not be available for rollback.
+ assertNull(rm.getAvailableRollback(TEST_APP_A));
+ assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+
+ // There should be no recently executed rollbacks for this package.
+ for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+ assertNotEquals(TEST_APP_A, info.targetPackage.packageName);
+ }
+
+ // 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));
+
+ // The app should now be available for rollback.
+ assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ // We should not have received any rollback requests yet.
+ // TODO: Possibly flaky if, by chance, some other app on device
+ // happens to be rolled back at the same time?
+ assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+ // Roll back the app.
+ RollbackTestUtils.rollback(rollback);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // Verify we received a broadcast for the rollback.
+ // TODO: Race condition between the timeout and when the broadcast is
+ // received could lead to test flakiness.
+ Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
+ assertNotNull(broadcast);
+ assertEquals(TEST_APP_A, broadcast.getData().getSchemeSpecificPart());
+ assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+ // Verify the recent rollback has been recorded.
+ rollback = null;
+ for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+ if (TEST_APP_A.equals(r.targetPackage.packageName)) {
+ assertNull(rollback);
+ rollback = r;
+ }
+ }
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ broadcastReceiver.unregister();
+ context.unregisterReceiver(enableRollbackReceiver);
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test that rollback data is properly persisted.
+ */
+ @Test
+ public void testRollbackDataPersistence() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ // Prep installation of TEST_APP_A
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // The app should now be available for rollback.
+ assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ // Reload the persisted data.
+ rm.reloadPersistedData();
+
+ // The app should still be available for rollback.
+ assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ rollback = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ // Roll back the app.
+ RollbackTestUtils.rollback(rollback);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // Verify the recent rollback has been recorded.
+ rollback = null;
+ for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+ if (TEST_APP_A.equals(r.targetPackage.packageName)) {
+ assertNull(rollback);
+ rollback = r;
+ }
+ }
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ // Reload the persisted data.
+ rm.reloadPersistedData();
+
+ // Verify the recent rollback is still recorded.
+ rollback = null;
+ for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+ if (TEST_APP_A.equals(r.targetPackage.packageName)) {
+ assertNull(rollback);
+ rollback = r;
+ }
+ }
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test explicit expiration of rollbacks.
+ * Does not test the scheduling aspects of rollback expiration.
+ */
+ @Test
+ public void testRollbackExpiration() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // The app should now be available for rollback.
+ assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollback);
+ assertEquals(TEST_APP_A, rollback.targetPackage.packageName);
+ assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
+ assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+
+ // Expire the rollback.
+ rm.expireRollbackForPackage(TEST_APP_A);
+
+ // The rollback should no longer be available.
+ assertNull(rm.getAvailableRollback(TEST_APP_A));
+ assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ private static final String NO_RESPONSE = "NO RESPONSE";
+
+ // Calls into the test app to process user data.
+ // Asserts if the user data could not be processed or was version
+ // incompatible with the previously processed user data.
+ private void processUserData(String packageName) throws Exception {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(packageName,
+ "com.android.tests.rollback.testapp.ProcessUserData"));
+ Context context = InstrumentationRegistry.getContext();
+
+ HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
+ handlerThread.start();
+
+ // It can sometimes take a while after rollback before the app will
+ // receive this broadcast, so try a few times in a loop.
+ String result = NO_RESPONSE;
+ for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
+ BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
+ context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getResultCode() == 1) {
+ resultQueue.add("OK");
+ } else {
+ // If the test app doesn't receive the broadcast or
+ // fails to set the result data, then getResultData
+ // here returns the initial NO_RESPONSE data passed to
+ // the sendOrderedBroadcast call.
+ resultQueue.add(getResultData());
+ }
+ }
+ }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
+
+ result = resultQueue.poll(10, TimeUnit.SECONDS);
+ if (result == null) {
+ result = "ProcessUserData broadcast timed out";
+ }
+ }
+
+ handlerThread.quit();
+ if (!"OK".equals(result)) {
+ fail(result);
+ }
+ }
+
+ /**
+ * Test that app user data is rolled back.
+ * TODO: Stop ignoring this test once user data rollback is supported.
+ */
+ @Ignore @Test
+ public void testUserDataRollback() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppV1.apk", false);
+ processUserData(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppV2.apk", true);
+ processUserData(TEST_APP_A);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ RollbackTestUtils.rollback(rollback);
+ processUserData(TEST_APP_A);
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test restrictions on rollback broadcast sender.
+ * A random app should not be able to send a PACKAGE_ROLLBACK_EXECUTED broadcast.
+ */
+ @Test
+ public void testRollbackBroadcastRestrictions() throws Exception {
+ RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
+ Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
+ Uri.fromParts("package", "com.android.tests.rollback.bogus", null));
+ try {
+ InstrumentationRegistry.getContext().sendBroadcast(broadcast);
+ fail("Succeeded in sending restricted broadcast from app context.");
+ } catch (SecurityException se) {
+ // Expected behavior.
+ }
+
+ // Confirm that we really haven't received the broadcast.
+ // TODO: How long to wait for the expected timeout?
+ assertNull(broadcastReceiver.poll(5, TimeUnit.SECONDS));
+
+ // TODO: Do we need to do this? Do we need to ensure this is always
+ // called, even when the test fails?
+ broadcastReceiver.unregister();
+ }
+
+ /**
+ * Regression test for rollback in the case when multiple apps are
+ * available for rollback at the same time.
+ */
+ @Test
+ public void testMultipleRollbackAvailable() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ // Prep installation of the test apps.
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.uninstall(TEST_APP_B);
+ RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
+ RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+ // Both test apps should now be available for rollback, and the
+ // targetPackage returned for rollback should be correct.
+ RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollbackA);
+ assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName);
+
+ RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+ assertNotNull(rollbackB);
+ assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName);
+
+ // Executing rollback should roll back the correct package.
+ RollbackTestUtils.rollback(rollbackA);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.rollback(rollbackB);
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test that the MANAGE_ROLLBACKS permission is required to call
+ * RollbackManager APIs.
+ */
+ @Test
+ public void testManageRollbacksPermission() throws Exception {
+ // We shouldn't be allowed to call any of the RollbackManager APIs
+ // without the MANAGE_ROLLBACKS permission.
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ try {
+ rm.getAvailableRollback(TEST_APP_A);
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+
+ try {
+ rm.getPackagesWithAvailableRollbacks();
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+
+ try {
+ rm.getRecentlyExecutedRollbacks();
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+
+ try {
+ // TODO: What if the implementation checks arguments for non-null
+ // first? Then this test isn't valid.
+ rm.executeRollback(null, null);
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+
+ try {
+ rm.reloadPersistedData();
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+
+ try {
+ rm.expireRollbackForPackage(TEST_APP_A);
+ fail("expected SecurityException");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+ }
+
+ /**
+ * Test rollback of multi-package installs.
+ * TODO: Stop ignoring this test once support for multi-package rollback
+ * is implemented.
+ */
+ @Ignore @Test
+ public void testMultiPackage() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+ // Prep installation of the test apps.
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.uninstall(TEST_APP_B);
+ RollbackTestUtils.installMultiPackage(false,
+ "RollbackTestAppAv1.apk",
+ "RollbackTestAppBv1.apk");
+ RollbackTestUtils.installMultiPackage(true,
+ "RollbackTestAppAv2.apk",
+ "RollbackTestAppBv2.apk");
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+ // TEST_APP_A should now be available for rollback.
+ assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ assertNotNull(rollback);
+
+ // TODO: Test the dependent apps for rollback are correct once we
+ // support that in the RollbackInfo API.
+
+ // Rollback the app. It should cause both test apps to be rolled
+ // back.
+ RollbackTestUtils.rollback(rollback);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+ // We should not see a recent rollback listed for TEST_APP_B
+ for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+ assertNotEquals(TEST_APP_B, r.targetPackage.packageName);
+ }
+
+ // TODO: Test the listed dependent apps for the recently executed
+ // rollback are correct once we support that in the RollbackInfo
+ // API.
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
new file mode 100644
index 000000000000..fbc3d8f1cd34
--- /dev/null
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.rollback;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.support.test.InstrumentationRegistry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Utilities to facilitate testing rollbacks.
+ */
+class RollbackTestUtils {
+
+ private static final String TAG = "RollbackTest";
+
+ static RollbackManager getRollbackManager() {
+ Context context = InstrumentationRegistry.getContext();
+ RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
+ if (rm == null) {
+ throw new AssertionError("Failed to get RollbackManager");
+ }
+ return rm;
+ }
+
+ /**
+ * Returns the version of the given package installed on device.
+ * Returns -1 if the package is not currently installed.
+ */
+ static long getInstalledVersion(String packageName) {
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo info = pm.getPackageInfo(packageName, 0);
+ return info.getLongVersionCode();
+ } catch (PackageManager.NameNotFoundException e) {
+ return -1;
+ }
+ }
+
+ private static void assertStatusSuccess(Intent result) {
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == -1) {
+ throw new AssertionError("PENDING USER ACTION");
+ } else if (status > 0) {
+ String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
+ throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
+ }
+ }
+
+ /**
+ * Uninstalls the given package.
+ * Does nothing if the package is not installed.
+ * @throws AssertionError if package can't be uninstalled.
+ */
+ static void uninstall(String packageName) throws InterruptedException, IOException {
+ // No need to uninstall if the package isn't installed.
+ if (getInstalledVersion(packageName) == -1) {
+ return;
+ }
+
+ Context context = InstrumentationRegistry.getContext();
+ PackageManager packageManager = context.getPackageManager();
+ PackageInstaller packageInstaller = packageManager.getPackageInstaller();
+ packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ /**
+ * Execute the given rollback.
+ * @throws AssertionError if the rollback fails.
+ */
+ static void rollback(RollbackInfo rollback) throws InterruptedException {
+ RollbackManager rm = getRollbackManager();
+ rm.executeRollback(rollback, LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ /**
+ * Installs the apk with the given name.
+ *
+ * @param resourceName name of class loader resource for the apk to
+ * install.
+ * @param enableRollback if rollback should be enabled.
+ * @throws AssertionError if the installation fails.
+ */
+ static void install(String resourceName, boolean enableRollback)
+ throws InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getContext();
+ PackageInstaller.Session session = null;
+ PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ if (enableRollback) {
+ params.setEnableRollback();
+ }
+ int sessionId = packageInstaller.createSession(params);
+ session = packageInstaller.openSession(sessionId);
+
+ ClassLoader loader = RollbackTest.class.getClassLoader();
+ try (OutputStream packageInSession = session.openWrite("package", 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);
+ }
+ }
+
+ // Commit the session (this will start the installation workflow).
+ session.commit(LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ /**
+ * Installs the apks with the given resource names as an atomic set.
+ *
+ * @param enableRollback if rollback should be enabled.
+ * @param resourceNames names of the class loader resource for the apks to
+ * install.
+ * @throws AssertionError if the installation fails.
+ */
+ static void installMultiPackage(boolean enableRollback, String... resourceNames)
+ throws InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getContext();
+ PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+
+ PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ multiPackageParams.setMultiPackage();
+ if (enableRollback) {
+ // TODO: Do we set this on the parent params, the child params, or
+ // both?
+ multiPackageParams.setEnableRollback();
+ }
+ int multiPackageId = packageInstaller.createSession(multiPackageParams);
+ PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
+
+ for (String resourceName : resourceNames) {
+ PackageInstaller.Session session = null;
+ PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+ PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ if (enableRollback) {
+ params.setEnableRollback();
+ }
+ int sessionId = packageInstaller.createSession(params);
+ session = packageInstaller.openSession(sessionId);
+
+ ClassLoader loader = RollbackTest.class.getClassLoader();
+ try (OutputStream packageInSession = session.openWrite("package", 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);
+ }
+ }
+ multiPackage.addChildSessionId(sessionId);
+ }
+
+ // Commit the session (this will start the installation workflow).
+ multiPackage.commit(LocalIntentSender.getIntentSender());
+ assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+ }
+
+ static void adoptShellPermissionIdentity(String... permissions) {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity(permissions);
+ }
+
+ static void dropShellPermissionIdentity() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+}
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 1e3a49bd8cc8..2c2afd4c6f1c 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -832,25 +832,23 @@ public class NetworkStatsTest {
0 /* operations */);
// Traffic measured for the root uid on the base interface if eBPF is in use.
- // Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation
- // overhead (20 bytes per packet), only for TX traffic.
final NetworkStats.Entry ebpfRootUidEntry = new NetworkStats.Entry(
baseIface, rootUid, SET_DEFAULT, TAG_NONE,
163577 /* rxBytes */,
187 /* rxPackets */,
- 1169942 /* txBytes */,
- 13902 /* txPackets */,
+ 17607 /* txBytes */,
+ 97 /* txPackets */,
0 /* operations */);
// Traffic measured for the root uid on the base interface if xt_qtaguid is in use.
// Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation
- // overhead (20 bytes per packet), in both directions.
+ // overhead (20 bytes per packet), in rx direction.
final NetworkStats.Entry xtRootUidEntry = new NetworkStats.Entry(
baseIface, rootUid, SET_DEFAULT, TAG_NONE,
31113087 /* rxBytes */,
22588 /* rxPackets */,
- 1169942 /* txBytes */,
- 13902 /* txPackets */,
+ 17607 /* txBytes */,
+ 97 /* txPackets */,
0 /* operations */);
final NetworkStats.Entry otherEntry = new NetworkStats.Entry(
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index 788924b1d3bf..90bf7b1a83ed 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -159,7 +159,7 @@ public class NetworkStatsFactoryTest {
assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L);
assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L);
assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 5766L);
+ assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 0L);
assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L);
assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L);
assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L);
@@ -170,6 +170,8 @@ public class NetworkStatsFactoryTest {
assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
+ assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
+
NetworkStatsFactory.clearStackedIfaces();
}
@@ -191,12 +193,12 @@ public class NetworkStatsFactoryTest {
// Stats snapshot before the download
stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before);
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 647888L);
+ assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 0L);
// Stats snapshot after the download
stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L);
+ assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 0L);
NetworkStatsFactory.clearStackedIfaces();
}
@@ -252,6 +254,15 @@ public class NetworkStatsFactoryTest {
assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
+ private static void assertNoStatsEntry(NetworkStats stats, String iface, int uid, int set,
+ int tag) {
+ final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO);
+ if (i >= 0) {
+ fail("unexpected NetworkStats entry at " + i);
+ }
+ }
+
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/net/res/raw/xt_qtaguid_with_clat
index 77e5c7ba8e62..6cd7499545be 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat
+++ b/tests/net/res/raw/xt_qtaguid_with_clat
@@ -7,7 +7,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0
8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0
9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 0 0 11058671 7892 312046 5113 11043898 7811 13117 61 1656 20 306544 5046 3230 38 2272 29
+10 wlan0 0x0 0 0 11058671 7892 0 0 11043898 7811 13117 61 1656 20 0 0 0 0 0 0
11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0
13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
@@ -41,3 +41,5 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8
43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+44 wlan0 0x0 1029 0 0 0 312046 5113 0 0 0 0 0 0 306544 5046 3230 38 2272 29
+45 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
index c78f84f3c655..9f86153a33cf 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
@@ -9,7 +9,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0
11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0
-12 wlan0 0x0 0 0 440746376 329772 8524052 130894 439660007 315369 232001 1276 854368 13127 7871216 121284 108568 1325 544268 8285
+12 wlan0 0x0 0 0 440746376 329772 0 0 439660007 315369 232001 1276 854368 13127 0 0 0 0 0 0
13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
@@ -185,3 +185,5 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
185 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
186 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
187 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+188 wlan0 0x0 1029 0 0 0 8524052 130894 0 0 0 0 0 0 7871216 121284 108568 1325 544268 8285
+189 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
index d0353876c8d3..ce4bcc3a3b43 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
@@ -9,7 +9,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
10 v4-wlan0 0x0 10106 0 1488 12 1488 12 0 0 1488 12 0 0 0 0 1488 12 0 0
11 v4-wlan0 0x0 10106 1 323981189 235142 3509032 84542 323979453 235128 1736 14 0 0 3502676 84363 6356 179 0 0
-12 wlan0 0x0 0 0 330187296 250652 5855801 94173 329106990 236273 226202 1255 854104 13124 5208040 84634 103637 1256 544124 8283
+12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
@@ -183,3 +183,5 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe
183 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
184 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
185 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+186 wlan0 0x0 1029 0 0 0 5855801 94173 0 0 0 0 0 0 5208040 84634 103637 1256 544124 8283
+187 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple
index 7f0e56f3ef6b..8c132e7e0a0e 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_simple
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_simple
@@ -1,5 +1,6 @@
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 4100 41 0 0 0 0 0 0 0 0
+2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0
3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 0 0 46860 213 4920 41 46860 213 4920 41 0 0 0 0 0 0 0 0
+4 wlan0 0x0 0 0 46860 213 0 0 46860 213 0 0 0 0 0 0 0 0 0 0
5 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+6 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
index 09430f2532fa..b4ea624524b3 100644
--- a/tools/aapt/ConfigDescription.h
+++ b/tools/aapt/ConfigDescription.h
@@ -29,7 +29,7 @@ struct ConfigDescription : public android::ResTable_config {
size = sizeof(android::ResTable_config);
}
- ConfigDescription(const android::ResTable_config&o) { // NOLINT(implicit)
+ ConfigDescription(const android::ResTable_config&o) { // NOLINT(google-explicit-constructor)
*static_cast<android::ResTable_config*>(this) = o;
size = sizeof(android::ResTable_config);
}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index ba498e19f837..c42a8889e373 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -170,6 +170,7 @@ cc_test_host {
srcs: [
"test/Builders.cpp",
"test/Common.cpp",
+ "test/Fixture.cpp",
"**/*_test.cpp",
] + toolSources,
static_libs: [
@@ -177,7 +178,10 @@ cc_test_host {
"libgmock",
],
defaults: ["aapt2_defaults"],
- data: ["integration-tests/CompileTest/**/*"],
+ data: [
+ "integration-tests/CompileTest/**/*",
+ "integration-tests/CommandTests/**/*"
+ ],
}
// ==========================================================
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 9460c9e596e9..5f664f5fdd5c 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -445,7 +445,7 @@ class XmlPrinter : public xml::ConstVisitor {
public:
using xml::ConstVisitor::Visit;
- XmlPrinter(Printer* printer) : printer_(printer) {
+ explicit XmlPrinter(Printer* printer) : printer_(printer) {
}
void Visit(const xml::Element* el) override {
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index dd5c751967b8..67ba895e51d1 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -113,7 +113,7 @@ struct ResourceNameRef {
ResourceNameRef() = default;
ResourceNameRef(const ResourceNameRef&) = default;
ResourceNameRef(ResourceNameRef&&) = default;
- ResourceNameRef(const ResourceName& rhs); // NOLINT(implicit)
+ ResourceNameRef(const ResourceName& rhs); // NOLINT(google-explicit-constructor)
ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
@@ -144,7 +144,7 @@ struct ResourceId {
ResourceId();
ResourceId(const ResourceId& rhs);
- ResourceId(uint32_t res_id); // NOLINT(implicit)
+ ResourceId(uint32_t res_id); // NOLINT(google-explicit-constructor)
ResourceId(uint8_t p, uint8_t t, uint16_t e);
bool is_valid() const;
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index bdee5c9d4909..4424a357c1dd 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -21,80 +21,97 @@
#include <string>
#include <vector>
+#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
#include "androidfw/StringPiece.h"
#include "util/Util.h"
+using android::base::StringPrintf;
using android::StringPiece;
namespace aapt {
-void Command::AddRequiredFlag(const StringPiece& name,
- const StringPiece& description, std::string* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- *value = arg.to_string();
+std::string GetSafePath(const StringPiece& arg) {
+#ifdef _WIN32
+ // If the path exceeds the maximum path length for Windows, encode the path using the
+ // extended-length prefix
+ std::wstring path16;
+ CHECK(android::base::UTF8PathToWindowsLongPath(arg.data(), &path16))
+ << "Failed to convert file path to UTF-16: file path " << arg.data();
+
+ std::string path8;
+ CHECK(android::base::WideToUTF8(path16, &path8))
+ << "Failed to convert file path back to UTF-8: file path " << arg.data();
+
+ return path8;
+#else
+ return arg.to_string();
+#endif
+}
+
+void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description,
+ std::string* value, uint32_t flags) {
+ auto func = [value, flags](const StringPiece& arg) -> bool {
+ *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+ flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
}
-void Command::AddRequiredFlagList(const StringPiece& name,
- const StringPiece& description,
- std::vector<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->push_back(arg.to_string());
+void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description,
+ std::vector<std::string>* value, uint32_t flags) {
+ auto func = [value, flags](const StringPiece& arg) -> bool {
+ value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+ flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
}
-void Command::AddOptionalFlag(const StringPiece& name,
- const StringPiece& description,
- Maybe<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- *value = arg.to_string();
+void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description,
+ Maybe<std::string>* value, uint32_t flags) {
+ auto func = [value, flags](const StringPiece& arg) -> bool {
+ *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+ flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalFlagList(const StringPiece& name,
- const StringPiece& description,
- std::vector<std::string>* value) {
- auto func = [value](const StringPiece& arg) -> bool {
- value->push_back(arg.to_string());
+void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+ std::vector<std::string>* value, uint32_t flags) {
+ auto func = [value, flags](const StringPiece& arg) -> bool {
+ value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+ flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalFlagList(const StringPiece& name,
- const StringPiece& description,
- std::unordered_set<std::string>* value) {
+void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+ std::unordered_set<std::string>* value) {
auto func = [value](const StringPiece& arg) -> bool {
value->insert(arg.to_string());
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+ flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
}
-void Command::AddOptionalSwitch(const StringPiece& name,
- const StringPiece& description, bool* value) {
+void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description,
+ bool* value) {
auto func = [value](const StringPiece& arg) -> bool {
*value = true;
return true;
};
- flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
+ flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 0, func));
}
void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) {
- subcommand->fullname_ = name_ + " " + subcommand->name_;
+ subcommand->full_subcommand_name_ = StringPrintf("%s %s", name_.data(), subcommand->name_.data());
if (experimental) {
experimental_subcommands_.push_back(std::move(subcommand));
} else {
@@ -102,14 +119,14 @@ void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool
}
}
-void Command::SetDescription(const android::StringPiece& description) {
+void Command::SetDescription(const StringPiece& description) {
description_ = description.to_string();
}
void Command::Usage(std::ostream* out) {
constexpr size_t kWidth = 50;
- *out << fullname_;
+ *out << full_subcommand_name_;
if (!subcommands_.empty()) {
*out << " [subcommand]";
@@ -117,7 +134,7 @@ void Command::Usage(std::ostream* out) {
*out << " [options]";
for (const Flag& flag : flags_) {
- if (flag.required) {
+ if (flag.is_required) {
*out << " " << flag.name << " arg";
}
}
@@ -160,29 +177,31 @@ void Command::Usage(std::ostream* out) {
out->flush();
}
-int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream* out_error) {
+int Command::Execute(const std::vector<StringPiece>& args, std::ostream* out_error) {
std::vector<std::string> file_args;
for (size_t i = 0; i < args.size(); i++) {
- StringPiece arg = args[i];
+ const StringPiece& arg = args[i];
if (*(arg.data()) != '-') {
// Continue parsing as the subcommand if the first argument matches one of the subcommands
if (i == 0) {
for (auto& subcommand : subcommands_) {
- if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+ if (arg == subcommand->name_ || (!subcommand->short_name_.empty()
+ && arg == subcommand->short_name_)) {
return subcommand->Execute(
- std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+ std::vector<StringPiece>(args.begin() + 1, args.end()), out_error);
}
}
for (auto& subcommand : experimental_subcommands_) {
- if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+ if (arg == subcommand->name_ || (!subcommand->short_name_.empty()
+ && arg == subcommand->short_name_)) {
return subcommand->Execute(
- std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+ std::vector<StringPiece>(args.begin() + 1, args.end()), out_error);
}
}
}
- file_args.push_back(arg.to_string());
+ file_args.push_back(GetSafePath(arg));
continue;
}
@@ -205,7 +224,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream
} else {
flag.action({});
}
- flag.parsed = true;
+ flag.found = true;
match = true;
break;
}
@@ -219,7 +238,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream
}
for (const Flag& flag : flags_) {
- if (flag.required && !flag.parsed) {
+ if (flag.is_required && !flag.found) {
*out_error << "missing required flag " << flag.name << "\n\n";
Usage(out_error);
return 1;
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 16949883d123..d21571d530d2 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -32,55 +32,83 @@ namespace aapt {
class Command {
public:
explicit Command(const android::StringPiece& name) : name_(name.to_string()),
- fullname_(name.to_string()) { }
+ short_name_(""),
+ full_subcommand_name_(name.to_string()) {}
+
explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
- : name_(name.to_string()), short_name_(short_name.to_string()), fullname_(name.to_string()) {}
+ : name_(name.to_string()), short_name_(short_name.to_string()),
+ full_subcommand_name_(name.to_string()) {}
+
virtual ~Command() = default;
+ // Behavior flags used with the following functions that change how the command flags are parsed
+ // displayed.
+ enum : uint32_t {
+ // Indicates the arguments are file or folder paths. On Windows, paths that exceed the maximum
+ // path length will be converted to use the extended path prefix '//?/'. Without this
+ // conversion, files with long paths cannot be opened.
+ kPath = 1 << 0,
+ };
+
void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
- std::string* value);
- void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece&
- description, std::vector<std::string>* value);
+ std::string* value, uint32_t flags = 0);
+
+ void AddRequiredFlagList(const android::StringPiece& name,
+ const android::StringPiece& description, std::vector<std::string>* value,
+ uint32_t flags = 0);
+
void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
- Maybe<std::string>* value);
+ Maybe<std::string>* value, uint32_t flags = 0);
+
void AddOptionalFlagList(const android::StringPiece& name,
- const android::StringPiece& description, std::vector<std::string>* value);
+ const android::StringPiece& description, std::vector<std::string>* value,
+ uint32_t flags = 0);
+
void AddOptionalFlagList(const android::StringPiece& name,
- const android::StringPiece& description, std::unordered_set<std::string>* value);
+ const android::StringPiece& description,
+ std::unordered_set<std::string>* value);
+
void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
- bool* value);
+ bool* value);
+
void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
void SetDescription(const android::StringPiece& name);
- /** Prints the help menu of the command. */
+ // Prints the help menu of the command.
void Usage(std::ostream* out);
- /**
- * Parses the command line arguments, sets the flag variable values, and runs the action of
- * the command. If the arguments fail to parse to the command and its subcommands, then the action
- * will not be run and the usage will be printed instead.
- **/
+ // Parses the command line arguments, sets the flag variable values, and runs the action of
+ // the command. If the arguments fail to parse to the command and its subcommands, then the action
+ // will not be run and the usage will be printed instead.
int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError);
- /** The action to preform when the command is executed. */
+ // The action to preform when the command is executed.
virtual int Action(const std::vector<std::string>& args) = 0;
private:
- struct Flag {
- std::string name;
- std::string description;
- std::function<bool(const android::StringPiece& value)> action;
- bool required;
- size_t num_args;
+ DISALLOW_COPY_AND_ASSIGN(Command);
- bool parsed;
+ struct Flag {
+ explicit Flag(const android::StringPiece& name, const android::StringPiece& description,
+ const bool is_required, const size_t num_args,
+ std::function<bool(const android::StringPiece& value)>&& action)
+ : name(name.to_string()), description(description.to_string()), is_required(is_required),
+ num_args(num_args), action(std::move(action)) {}
+
+ const std::string name;
+ const std::string description;
+ const bool is_required;
+ const size_t num_args;
+ const std::function<bool(const android::StringPiece& value)> action;
+ bool found = false;
};
- std::string description_;
- std::string name_;
- std::string short_name_;
- std::string fullname_;
+ const std::string name_;
+ const std::string short_name_;
+ std::string description_ = "";
+ std::string full_subcommand_name_;
+
std::vector<Flag> flags_;
std::vector<std::unique_ptr<Command>> subcommands_;
std::vector<std::unique_ptr<Command>> experimental_subcommands_;
diff --git a/tools/aapt2/cmd/Command_test.cpp b/tools/aapt2/cmd/Command_test.cpp
new file mode 100644
index 000000000000..65608fdf64a7
--- /dev/null
+++ b/tools/aapt2/cmd/Command_test.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include "Command.h"
+
+#include "test/Test.h"
+
+using ::testing::Eq;
+
+namespace aapt {
+
+class TestCommand : public Command {
+ public:
+ explicit TestCommand() : Command("command") {}
+ int Action(const std::vector<std::string>& args) override {
+ args_ = args;
+ return 0;
+ }
+
+ std::vector<std::string> args_;
+};
+
+#ifdef _WIN32
+TEST(CommandTest, LongFullyQualifiedPathWindows) {
+ TestCommand command;
+ std::string required_flag;
+ command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath);
+ Maybe<std::string> optional_flag;
+ command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath);
+ std::vector<std::string> required_flag_list;
+ command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath);
+ std::vector<std::string> optional_flag_list;
+ command.AddOptionalFlagList("--olflag", "", &optional_flag_list, Command::kPath);
+ std::string non_path_flag;
+ command.AddRequiredFlag("--nflag", "", &non_path_flag);
+
+ const std::string kLongPath =
+ "C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp"
+ "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65"
+ "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+ "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+ "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+ "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+ "\\out\\resources-minified.ap_";
+
+ const std::string kExpected =
+ "\\\\?\\C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp"
+ "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65"
+ "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+ "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+ "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+ "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+ "\\out\\resources-minified.ap_";
+
+
+ ASSERT_THAT(command.Execute({"--rflag", kLongPath,
+ "--oflag", kLongPath,
+ "--rlflag", kLongPath,
+ "--rlflag", kLongPath,
+ "--olflag", kLongPath,
+ "--olflag", kLongPath,
+ "--nflag", kLongPath,
+ kLongPath, kLongPath}, &std::cerr), Eq(0));
+
+ ASSERT_THAT(required_flag, Eq(kExpected));
+ ASSERT_THAT(optional_flag, Eq(kExpected));
+ ASSERT_THAT(required_flag_list.size(), Eq(2));
+ ASSERT_THAT(required_flag_list[0], Eq(kExpected));
+ ASSERT_THAT(required_flag_list[1], Eq(kExpected));
+ ASSERT_THAT(optional_flag_list.size(), Eq(2));
+ ASSERT_THAT(optional_flag_list[0], Eq(kExpected));
+ ASSERT_THAT(optional_flag_list[1], Eq(kExpected));
+
+ // File arguments should also be converted to use the long path prefix
+ ASSERT_THAT(command.args_.size(), Eq(2));
+ ASSERT_THAT(command.args_[0], Eq(kExpected));
+ ASSERT_THAT(command.args_[1], Eq(kExpected));
+
+ // Do not convert flags that are not marged as paths
+ ASSERT_THAT(non_path_flag, Eq(kLongPath));
+}
+#endif
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index f63a0745690b..52375a39b93f 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -584,7 +584,7 @@ static bool CompileFile(IAaptContext* context, const CompileOptions& options,
class CompileContext : public IAaptContext {
public:
- CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
+ explicit CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
}
PackageType GetPackageType() override {
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index c429d5f5d4b2..9b32cb3750a5 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -44,13 +44,13 @@ class CompileCommand : public Command {
explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
diagnostic_(diagnostic) {
SetDescription("Compiles resources to be linked into an apk.");
- AddRequiredFlag("-o", "Output path", &options_.output_path);
- AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir);
+ AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath);
+ AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath);
AddOptionalFlag("--zip", "Zip file containing the res directory to scan for resources",
- &options_.res_zip);
+ &options_.res_zip, Command::kPath);
AddOptionalFlag("--output-text-symbols",
"Generates a text file containing the resource symbols in the\n"
- "specified file", &options_.generate_text_symbols_path);
+ "specified file", &options_.generate_text_symbols_path, Command::kPath);
AddOptionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
"(en-XA and ar-XB)", &options_.pseudolocalize);
AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch);
@@ -70,8 +70,9 @@ class CompileCommand : public Command {
Maybe<std::string> visibility_;
};
-int Compile(IAaptContext* context, io::IFileCollection* inputs,
- IArchiveWriter* output_writer, CompileOptions& options);
+int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer,
+ CompileOptions& options);
+
}// namespace aapt
#endif //AAPT2_COMPILE_H
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 4492f6b49cf0..85f90806752f 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -60,16 +60,17 @@ class IApkSerializer {
class BinaryApkSerializer : public IApkSerializer {
public:
BinaryApkSerializer(IAaptContext* context, const Source& source,
- const TableFlattenerOptions& options)
- : IApkSerializer(context, source), tableFlattenerOptions_(options) {}
+ const TableFlattenerOptions& table_flattener_options,
+ const XmlFlattenerOptions& xml_flattener_options)
+ : IApkSerializer(context, source),
+ table_flattener_options_(table_flattener_options),
+ xml_flattener_options_(xml_flattener_options) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) override {
BigBuffer buffer(4096);
- XmlFlattenerOptions options = {};
- options.use_utf16 = utf16;
- options.keep_raw_values = true;
- XmlFlattener flattener(&buffer, options);
+ xml_flattener_options_.use_utf16 = utf16;
+ XmlFlattener flattener(&buffer, xml_flattener_options_);
if (!flattener.Consume(context_, xml)) {
return false;
}
@@ -80,7 +81,7 @@ class BinaryApkSerializer : public IApkSerializer {
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
BigBuffer buffer(4096);
- TableFlattener table_flattener(tableFlattenerOptions_, &buffer);
+ TableFlattener table_flattener(table_flattener_options_, &buffer);
if (!table_flattener.Consume(context_, table)) {
return false;
}
@@ -136,7 +137,8 @@ class BinaryApkSerializer : public IApkSerializer {
}
private:
- TableFlattenerOptions tableFlattenerOptions_;
+ TableFlattenerOptions table_flattener_options_;
+ XmlFlattenerOptions xml_flattener_options_;
DISALLOW_COPY_AND_ASSIGN(BinaryApkSerializer);
};
@@ -252,13 +254,15 @@ class Context : public IAaptContext {
};
int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer,
- ApkFormat output_format, TableFlattenerOptions& options) {
+ ApkFormat output_format, TableFlattenerOptions table_flattener_options,
+ XmlFlattenerOptions xml_flattener_options) {
// Do not change the ordering of strings in the values string pool
- options.sort_stringpool_entries = false;
+ table_flattener_options.sort_stringpool_entries = false;
unique_ptr<IApkSerializer> serializer;
if (output_format == ApkFormat::kBinary) {
- serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), options));
+ serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options,
+ xml_flattener_options));
} else if (output_format == ApkFormat::kProto) {
serializer.reset(new ProtoApkSerializer(context, apk->GetSource()));
} else {
@@ -378,7 +382,8 @@ int ConvertCommand::Action(const std::vector<std::string>& args) {
return 1;
}
- return Convert(&context, apk.get(), writer.get(), format, options_);
+ return Convert(&context, apk.get(), writer.get(), format, table_flattener_options_,
+ xml_flattener_options_);
}
} // namespace aapt
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 6a6719c91b58..7e2029dfc4d2 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -20,6 +20,7 @@
#include "Command.h"
#include "LoadedApk.h"
#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
namespace aapt {
@@ -27,14 +28,18 @@ class ConvertCommand : public Command {
public:
explicit ConvertCommand() : Command("convert") {
SetDescription("Converts an apk between binary and proto formats.");
- AddRequiredFlag("-o", "Output path", &output_path_);
+ AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath);
AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. "
"Accepted values are '%s' and '%s'. When not set, defaults to '%s'.",
kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_);
AddOptionalSwitch("--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
- "This decreases APK size at the cost of resource retrieval performance.",
- &options_.use_sparse_entries);
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &table_flattener_options_.use_sparse_entries);
+ AddOptionalSwitch("--keep-raw-values",
+ android::base::StringPrintf("Preserve raw attribute values in xml files when using the"
+ " '%s' output format", kOutputFormatBinary),
+ &xml_flattener_options_.keep_raw_values);
AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
}
@@ -44,14 +49,16 @@ class ConvertCommand : public Command {
const static char* kOutputFormatProto;
const static char* kOutputFormatBinary;
- TableFlattenerOptions options_;
+ TableFlattenerOptions table_flattener_options_;
+ XmlFlattenerOptions xml_flattener_options_;
std::string output_path_;
Maybe<std::string> output_format_;
bool verbose_ = false;
};
int Convert(IAaptContext* context, LoadedApk* input, IArchiveWriter* output_writer,
- ApkFormat output_format, TableFlattenerOptions& options);
+ ApkFormat output_format,TableFlattenerOptions table_flattener_options,
+ XmlFlattenerOptions xml_flattener_options);
} // namespace aapt
diff --git a/tools/aapt2/cmd/Convert_test.cpp b/tools/aapt2/cmd/Convert_test.cpp
new file mode 100644
index 000000000000..2e4315086105
--- /dev/null
+++ b/tools/aapt2/cmd/Convert_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#include "Convert.h"
+
+#include "LoadedApk.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using ConvertTest = CommandTestFixture;
+
+TEST_F(ConvertTest, RemoveRawXmlStrings) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+ compiled_files_dir, &diag));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ std::vector<std::string> link_args = {
+ "--manifest", GetDefaultManifest(),
+ "-o", out_apk,
+ "--keep-raw-values",
+ "--proto-format"
+ };
+
+ ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+ const std::string out_convert_apk = GetTestPath("out_convert.apk");
+ std::vector<android::StringPiece> convert_args = {
+ "-o", out_convert_apk,
+ "--output-format", "binary",
+ out_apk,
+ };
+ ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
+
+ // Load the binary xml tree
+ android::ResXMLTree tree;
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
+ AssertLoadXml(apk.get(), "res/xml/test.xml", &tree);
+
+ // Check that the raw string index has not been assigned
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
+}
+
+TEST_F(ConvertTest, KeepRawXmlStrings) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+ compiled_files_dir, &diag));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ std::vector<std::string> link_args = {
+ "--manifest", GetDefaultManifest(),
+ "-o", out_apk,
+ "--keep-raw-values",
+ "--proto-format"
+ };
+
+ ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+ const std::string out_convert_apk = GetTestPath("out_convert.apk");
+ std::vector<android::StringPiece> convert_args = {
+ "-o", out_convert_apk,
+ "--output-format", "binary",
+ "--keep-raw-values",
+ out_apk,
+ };
+ ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
+
+ // Load the binary xml tree
+ android::ResXMLTree tree;
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
+ AssertLoadXml(apk.get(), "res/xml/test.xml", &tree);
+
+ // Check that the raw string index has been set to the correct string pool entry
+ int32_t raw_index = tree.getAttributeValueStringID(0);
+ ASSERT_THAT(raw_index, Ne(-1));
+ EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1b5601d451a7..729447ee1de5 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -78,7 +78,7 @@ namespace aapt {
class LinkContext : public IAaptContext {
public:
- LinkContext(IDiagnostics* diagnostics)
+ explicit LinkContext(IDiagnostics* diagnostics)
: diagnostics_(diagnostics), name_mangler_({}), symbols_(&name_mangler_) {
}
@@ -163,7 +163,7 @@ class LinkContext : public IAaptContext {
// See b/37498913.
class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
public:
- FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
+ explicit FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
}
virtual ~FeatureSplitSymbolTableDelegate() = default;
@@ -1545,7 +1545,8 @@ class Linker {
// to the IArchiveWriter.
bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
ResourceTable* table) {
- const bool keep_raw_values = context_->GetPackageType() == PackageType::kStaticLib;
+ const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib)
+ || options_.keep_raw_values;
bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values,
true /*utf16*/, options_.output_format, writer);
if (!result) {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 950dac204dde..f70470acb3d8 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -75,6 +75,7 @@ struct LinkOptions {
// Flattening options.
TableFlattenerOptions table_flattener_options;
+ bool keep_raw_values = false;
// Split APK options.
TableSplitterOptions table_splitter_options;
@@ -100,24 +101,26 @@ class LinkCommand : public Command {
explicit LinkCommand(IDiagnostics* diag) : Command("link", "l"),
diag_(diag) {
SetDescription("Links resources into an apk.");
- AddRequiredFlag("-o", "Output path.", &options_.output_path);
+ AddRequiredFlag("-o", "Output path.", &options_.output_path, Command::kPath);
AddRequiredFlag("--manifest", "Path to the Android manifest to build.",
- &options_.manifest_path);
- AddOptionalFlagList("-I", "Adds an Android APK to link against.", &options_.include_paths);
+ &options_.manifest_path, Command::kPath);
+ AddOptionalFlagList("-I", "Adds an Android APK to link against.", &options_.include_paths,
+ Command::kPath);
AddOptionalFlagList("-A", "An assets directory to include in the APK. These are unprocessed.",
- &options_.assets_dirs);
+ &options_.assets_dirs, Command::kPath);
AddOptionalFlagList("-R", "Compilation unit to link, using `overlay` semantics.\n"
- "The last conflicting resource given takes precedence.", &overlay_arg_list_);
+ "The last conflicting resource given takes precedence.", &overlay_arg_list_,
+ Command::kPath);
AddOptionalFlag("--package-id",
"Specify the package ID to use for this app. Must be greater or equal to\n"
"0x7f and can't be used with --static-lib or --shared-lib.", &package_id_);
AddOptionalFlag("--java", "Directory in which to generate R.java.",
- &options_.generate_java_class_path);
+ &options_.generate_java_class_path, Command::kPath);
AddOptionalFlag("--proguard", "Output file for generated Proguard rules.",
- &options_.generate_proguard_rules_path);
+ &options_.generate_proguard_rules_path, Command::kPath);
AddOptionalFlag("--proguard-main-dex",
"Output file for generated Proguard rules for the main dex.",
- &options_.generate_main_dex_proguard_rules_path);
+ &options_.generate_main_dex_proguard_rules_path, Command::kPath);
AddOptionalSwitch("--proguard-conditional-keep-rules",
"Generate conditional Proguard keep rules.",
&options_.generate_conditional_proguard_rules);
@@ -242,6 +245,8 @@ class LinkCommand : public Command {
&options_.extensions_to_not_compress);
AddOptionalSwitch("--no-compress", "Do not compress any resources.",
&options_.do_not_compress_anything);
+ AddOptionalSwitch("--keep-raw-values", "Preserve raw attribute values in xml files.",
+ &options_.keep_raw_values);
AddOptionalSwitch("--warn-manifest-validation",
"Treat manifest validation errors as warnings.",
&options_.manifest_fixer_options.warn_validation);
@@ -250,7 +255,6 @@ class LinkCommand : public Command {
"Syntax: path/to/output.apk:<config>[,<config>[...]].\n"
"On Windows, use a semicolon ';' separator instead.",
&split_args_);
- AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
AddOptionalSwitch("--debug-mode",
"Inserts android:debuggable=\"true\" in to the application node of the\n"
"manifest, making the application debuggable even on production devices.",
@@ -258,6 +262,7 @@ class LinkCommand : public Command {
AddOptionalSwitch("--strict-visibility",
"Do not allow overlays with different visibility levels.",
&options_.strict_visibility);
+ AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
}
int Action(const std::vector<std::string>& args) override;
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
new file mode 100644
index 000000000000..3c8b72d3cb2c
--- /dev/null
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#include "Link.h"
+
+#include "LoadedApk.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using LinkTest = CommandTestFixture;
+
+TEST_F(LinkTest, RemoveRawXmlStrings) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+ compiled_files_dir, &diag));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ std::vector<std::string> link_args = {
+ "--manifest", GetDefaultManifest(),
+ "-o", out_apk,
+ };
+
+ ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+ // Load the binary xml tree
+ android::ResXMLTree tree;
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
+ AssertLoadXml(apk.get(), "res/xml/test.xml", &tree);
+
+ // Check that the raw string index has not been assigned
+ EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
+}
+
+TEST_F(LinkTest, KeepRawXmlStrings) {
+ StdErrDiagnostics diag;
+ const std::string compiled_files_dir = GetTestPath("compiled");
+ ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+ compiled_files_dir, &diag));
+
+ const std::string out_apk = GetTestPath("out.apk");
+ std::vector<std::string> link_args = {
+ "--manifest", GetDefaultManifest(),
+ "-o", out_apk,
+ "--keep-raw-values"
+ };
+
+ ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+ // Load the binary xml tree
+ android::ResXMLTree tree;
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
+ AssertLoadXml(apk.get(), "res/xml/test.xml", &tree);
+
+ // Check that the raw string index has been set to the correct string pool entry
+ int32_t raw_index = tree.getAttributeValueStringID(0);
+ ASSERT_THAT(raw_index, Ne(-1));
+ EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 43bc216382fa..d07305bc3e04 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -61,9 +61,10 @@ class OptimizeCommand : public Command {
public:
explicit OptimizeCommand() : Command("optimize") {
SetDescription("Preforms resource optimizations on an apk.");
- AddOptionalFlag("-o", "Path to the output APK.", &options_.output_path);
- AddOptionalFlag("-d", "Path to the output directory (for splits).", &options_.output_dir);
- AddOptionalFlag("-x", "Path to XML configuration file.", &config_path_);
+ AddOptionalFlag("-o", "Path to the output APK.", &options_.output_path, Command::kPath);
+ AddOptionalFlag("-d", "Path to the output directory (for splits).", &options_.output_dir,
+ Command::kPath);
+ AddOptionalFlag("-x", "Path to XML configuration file.", &config_path_, Command::kPath);
AddOptionalSwitch("-p", "Print the multi APK artifacts and exit.", &print_only_);
AddOptionalFlag(
"--target-densities",
diff --git a/tools/aapt2/integration-tests/CommandTests/android-28.jar b/tools/aapt2/integration-tests/CommandTests/android-28.jar
new file mode 100644
index 000000000000..ef7576d17c6d
--- /dev/null
+++ b/tools/aapt2/integration-tests/CommandTests/android-28.jar
Binary files differ
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index 38b4860d1d61..f9656d112b7b 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -49,7 +49,7 @@ class KeepSet {
public:
KeepSet() = default;
- KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) {
+ explicit KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) {
}
inline void AddManifestClass(const UsageLocation& file, const std::string& class_name) {
diff --git a/tools/aapt2/link/XmlCompatVersioner.h b/tools/aapt2/link/XmlCompatVersioner.h
index 099e23c9e479..998061806279 100644
--- a/tools/aapt2/link/XmlCompatVersioner.h
+++ b/tools/aapt2/link/XmlCompatVersioner.h
@@ -55,7 +55,7 @@ class XmlCompatVersioner {
public:
using Rules = std::unordered_map<ResourceId, std::unique_ptr<IDegradeRule>>;
- XmlCompatVersioner(const Rules* rules);
+ explicit XmlCompatVersioner(const Rules* rules);
std::vector<std::unique_ptr<xml::XmlResource>> Process(IAaptContext* context,
xml::XmlResource* doc,
@@ -83,7 +83,7 @@ struct ReplacementAttr {
class DegradeToManyRule : public IDegradeRule {
public:
- DegradeToManyRule(std::vector<ReplacementAttr> attrs);
+ explicit DegradeToManyRule(std::vector<ReplacementAttr> attrs);
virtual ~DegradeToManyRule() = default;
std::vector<DegradeResult> Degrade(const xml::Element& src_el, const xml::Attribute& src_attr,
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 51a2e373596a..2d8bd02a3799 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -71,7 +71,7 @@ class SymbolTable {
bool is_dynamic = false;
};
- SymbolTable(NameMangler* mangler);
+ explicit SymbolTable(NameMangler* mangler);
// Overrides the default ISymbolTableDelegate, which allows a custom defined strategy for
// looking up resources from a set of sources.
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 50b41f1cb1e8..777ca5c72619 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -173,10 +173,12 @@ class ValueEqImpl : public ::testing::MatcherInterface<T> {
template <typename TValue>
class ValueEqMatcher {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
ValueEqMatcher(TValue expected) : expected_(std::move(expected)) {
}
template <typename T>
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator ::testing::Matcher<T>() const {
return ::testing::Matcher<T>(new ValueEqImpl<T>(&expected_));
}
@@ -188,10 +190,12 @@ class ValueEqMatcher {
template <typename TValue>
class ValueEqPointerMatcher {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
ValueEqPointerMatcher(const TValue* expected) : expected_(expected) {
}
template <typename T>
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator ::testing::Matcher<T>() const {
return ::testing::Matcher<T>(new ValueEqImpl<T>(expected_));
}
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
new file mode 100644
index 000000000000..aae79fafc0a6
--- /dev/null
+++ b/tools/aapt2/test/Fixture.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "test/Fixture.h"
+
+#include <dirent.h>
+
+#include "android-base/errors.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
+#include "androidfw/StringPiece.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "cmd/Compile.h"
+#include "cmd/Link.h"
+#include "io/FileStream.h"
+#include "io/Util.h"
+#include "util/Files.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+void ClearDirectory(const android::StringPiece& path) {
+ const std::string root_dir = path.to_string();
+ std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
+ if (!dir) {
+ StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
+ return;
+ }
+
+ while (struct dirent* entry = readdir(dir.get())) {
+ // Do not delete hidden files and do not recurse to the parent of this directory
+ if (util::StartsWith(entry->d_name, ".")) {
+ continue;
+ }
+
+ std::string full_path = file::BuildPath({root_dir, entry->d_name});
+ if (file::GetFileType(full_path) == file::FileType::kDirectory) {
+ ClearDirectory(full_path);
+#ifdef _WIN32
+ _rmdir(full_path.c_str());
+#else
+ rmdir(full_path.c_str());
+#endif
+ } else {
+ android::base::utf8::unlink(full_path.c_str());
+ }
+ }
+}
+
+void TestDirectoryFixture::SetUp() {
+ temp_dir_ = file::BuildPath({android::base::GetExecutableDirectory(),
+ "_temp",
+ testing::UnitTest::GetInstance()->current_test_case()->name(),
+ testing::UnitTest::GetInstance()->current_test_info()->name()});
+ ASSERT_TRUE(file::mkdirs(temp_dir_));
+ ClearDirectory(temp_dir_);
+}
+
+void TestDirectoryFixture::TearDown() {
+ ClearDirectory(temp_dir_);
+}
+
+bool TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
+ CHECK(util::StartsWith(path, temp_dir_))
+ << "Attempting to create a file outside of test temporary directory.";
+
+ // Create any intermediate directories specified in the path
+ auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep);
+ if (pos != path.rend()) {
+ std::string dirs = path.substr(0, (&*pos - path.data()));
+ file::mkdirs(dirs);
+ }
+
+ return android::base::WriteStringToFile(contents, path);
+}
+
+bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
+ const android::StringPiece& out_dir, IDiagnostics* diag) {
+ CHECK(WriteFile(path, contents));
+ CHECK(file::mkdirs(out_dir.data()));
+ return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
+}
+
+bool CommandTestFixture::Link(const std::vector<std::string>& args,
+ const android::StringPiece& flat_dir, IDiagnostics* diag) {
+ std::vector<android::StringPiece> link_args;
+ for(const std::string& arg : args) {
+ link_args.emplace_back(arg);
+ }
+
+ // Link against the android SDK
+ std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
+ "integration-tests", "CommandTests",
+ "android-28.jar"});
+ link_args.insert(link_args.end(), {"-I", android_sdk});
+
+ // Add the files from the compiled resources directory to the link file arguments
+ Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
+ if (compiled_files) {
+ for (std::string& compile_file : compiled_files.value()) {
+ compile_file = file::BuildPath({flat_dir, compile_file});
+ link_args.emplace_back(std::move(compile_file));
+ }
+ }
+
+ return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
+}
+
+std::string CommandTestFixture::GetDefaultManifest() {
+ const std::string manifest_file = GetTestPath("AndroidManifest.xml");
+ CHECK(WriteFile(manifest_file, R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.aapt.command.test">
+ </manifest>)"));
+ return manifest_file;
+}
+
+void CommandTestFixture::AssertLoadXml(LoadedApk *apk, const android::StringPiece &xml_path,
+ android::ResXMLTree *out_tree) {
+ ASSERT_THAT(apk, Ne(nullptr));
+
+ io::IFile* file = apk->GetFileCollection()->FindFile(xml_path);
+ ASSERT_THAT(file, Ne(nullptr));
+
+ std::unique_ptr<io::IData> data = file->OpenAsData();
+ ASSERT_THAT(data, Ne(nullptr));
+
+ out_tree->setTo(data->data(), data->size());
+ ASSERT_THAT(out_tree->getError(), Eq(android::OK));
+ while (out_tree->next() != android::ResXMLTree::START_TAG) {
+ ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+ ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+ }
+}
+
+} // namespace aapt \ No newline at end of file
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
new file mode 100644
index 000000000000..89d3b7b751a0
--- /dev/null
+++ b/tools/aapt2/test/Fixture.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef AAPT_TEST_FIXTURE_H
+#define AAPT_TEST_FIXTURE_H
+
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "io/Util.h"
+#include "util/Files.h"
+#include "LoadedApk.h"
+
+namespace aapt {
+
+class TestDirectoryFixture : public ::testing::Test {
+ public:
+ TestDirectoryFixture() = default;
+ virtual ~TestDirectoryFixture() = default;
+
+ // Creates the test directory or clears its contents if it contains previously created files.
+ void SetUp() override;
+
+ // Clears the contents of the test directory.
+ void TearDown() override;
+
+ // Retrieve the test directory of the fixture.
+ const android::StringPiece GetTestDirectory() {
+ return temp_dir_;
+ }
+
+ // Retrieves the absolute path of the specified relative path in the test directory. Directories
+ // should be separated using forward slashes ('/'), and these slashes will be translated to
+ // backslashes when running Windows tests.
+ const std::string GetTestPath(const android::StringPiece& path) {
+ std::string base = temp_dir_;
+ for (android::StringPiece part : util::Split(path, '/')) {
+ file::AppendPath(&base, part);
+ }
+ return base;
+ }
+
+ // Creates a file with the specified contents, creates any intermediate directories in the
+ // process. The file path must be an absolute path within the test directory.
+ bool WriteFile(const std::string& path, const std::string& contents);
+
+ private:
+ std::string temp_dir_;
+ DISALLOW_COPY_AND_ASSIGN(TestDirectoryFixture);
+};
+
+class CommandTestFixture : public TestDirectoryFixture {
+ public:
+ CommandTestFixture() = default;
+ virtual ~CommandTestFixture() = default;
+
+ // Wries the contents of the file to the specified path. The file is compiled and the flattened
+ // file is written to the out directory.
+ bool CompileFile(const std::string& path, const std::string& contents,
+ const android::StringPiece& flat_out_dir, IDiagnostics* diag);
+
+ // Executes the link command with the specified arguments. The flattened files residing in the
+ // flat directory will be added to the link command as file arguments.
+ bool Link(const std::vector<std::string>& args, const android::StringPiece& flat_dir,
+ IDiagnostics* diag);
+
+ // Creates a minimal android manifest within the test directory and returns the file path.
+ std::string GetDefaultManifest();
+
+ // Asserts that loading the tree from the specified file in the apk succeeds.
+ void AssertLoadXml(LoadedApk* apk, const android::StringPiece& xml_path,
+ android::ResXMLTree* out_tree);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
+};
+
+} // namespace aapt
+
+#endif // AAPT_TEST_FIXTURE_H \ No newline at end of file
diff --git a/tools/aapt2/test/Test.h b/tools/aapt2/test/Test.h
index a24c01cd4137..7d96d1f08c0d 100644
--- a/tools/aapt2/test/Test.h
+++ b/tools/aapt2/test/Test.h
@@ -23,5 +23,6 @@
#include "test/Builders.h"
#include "test/Common.h"
#include "test/Context.h"
+#include "test/Fixture.h"
#endif // AAPT_TEST_TEST_H
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5cfbbf2485e0..7b268bb283f4 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -180,6 +180,17 @@ void AppendPath(std::string* base, StringPiece part) {
base->append(part.data(), part.size());
}
+std::string BuildPath(std::vector<const StringPiece>&& args) {
+ if (args.empty()) {
+ return "";
+ }
+ std::string out = args[0].to_string();
+ for (int i = 1; i < args.size(); i++) {
+ file::AppendPath(&out, args[i]);
+ }
+ return out;
+}
+
std::string PackageToPath(const StringPiece& package) {
std::string out_path;
for (const StringPiece& part : util::Tokenize(package, '.')) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 219e1a07af95..58395526b193 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -57,6 +57,9 @@ FileType GetFileType(const std::string& path);
// Appends a path to `base`, separated by the directory separator.
void AppendPath(std::string* base, android::StringPiece part);
+// Concatenates the list of paths and separates each part with the directory separator.
+std::string BuildPath(std::vector<const android::StringPiece>&& args);
+
// Makes all the directories in `path`. The last element in the path is interpreted as a directory.
bool mkdirs(const std::string& path);
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
index 031276c8b885..047e1a581330 100644
--- a/tools/aapt2/util/Maybe.h
+++ b/tools/aapt2/util/Maybe.h
@@ -44,12 +44,12 @@ class Maybe {
Maybe(const Maybe& rhs);
template <typename U>
- Maybe(const Maybe<U>& rhs); // NOLINT(implicit)
+ Maybe(const Maybe<U>& rhs); // NOLINT(google-explicit-constructor)
Maybe(Maybe&& rhs) noexcept;
template <typename U>
- Maybe(Maybe<U>&& rhs); // NOLINT(implicit)
+ Maybe(Maybe<U>&& rhs); // NOLINT(google-explicit-constructor)
Maybe& operator=(const Maybe& rhs);
@@ -64,12 +64,12 @@ class Maybe {
/**
* Construct a Maybe holding a value.
*/
- Maybe(const T& value); // NOLINT(implicit)
+ Maybe(const T& value); // NOLINT(google-explicit-constructor)
/**
* Construct a Maybe holding a value.
*/
- Maybe(T&& value); // NOLINT(implicit)
+ Maybe(T&& value); // NOLINT(google-explicit-constructor)
/**
* True if this holds a value, false if
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
new file mode 100644
index 000000000000..fa2ab30ef479
--- /dev/null
+++ b/wifi/java/android/net/wifi/DppStatusCallback.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
+ * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
+ * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
+ * Handler, DppStatusCallback)}
+ * @hide
+ */
+@SystemApi
+public abstract class DppStatusCallback {
+ /**
+ * DPP Success event: Configuration sent (Configurator mode).
+ */
+ public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+ /** @hide */
+ @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
+ DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DppSuccessStatusCode {}
+
+ /**
+ * DPP Progress event: Initial authentication with peer succeeded.
+ */
+ public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+ /**
+ * DPP Progress event: Peer requires more time to process bootstrapping.
+ */
+ public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+ /** @hide */
+ @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
+ DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+ DPP_EVENT_PROGRESS_RESPONSE_PENDING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DppProgressStatusCode {}
+
+ /**
+ * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
+ */
+ public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
+
+ /**
+ * DPP Failure event: Bootstrapping/Authentication initialization process failure.
+ */
+ public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
+
+ /**
+ * DPP Failure event: Both devices are implementing the same role and are incompatible.
+ */
+ public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+ /**
+ * DPP Failure event: Configuration process has failed due to malformed message.
+ */
+ public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
+
+ /**
+ * DPP Failure event: DPP request while in another DPP exchange.
+ */
+ public static final int DPP_EVENT_FAILURE_BUSY = -5;
+
+ /**
+ * DPP Failure event: No response from the peer.
+ */
+ public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
+
+ /**
+ * DPP Failure event: General protocol failure.
+ */
+ public static final int DPP_EVENT_FAILURE = -7;
+
+ /**
+ * DPP Failure event: Feature or option is not supported.
+ */
+ public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+ /**
+ * DPP Failure event: Invalid network provided to DPP configurator.
+ * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+ */
+ public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+ /** @hide */
+ @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
+ DPP_EVENT_FAILURE_INVALID_URI,
+ DPP_EVENT_FAILURE_AUTHENTICATION,
+ DPP_EVENT_FAILURE_NOT_COMPATIBLE,
+ DPP_EVENT_FAILURE_CONFIGURATION,
+ DPP_EVENT_FAILURE_BUSY,
+ DPP_EVENT_FAILURE_TIMEOUT,
+ DPP_EVENT_FAILURE,
+ DPP_EVENT_FAILURE_NOT_SUPPORTED,
+ DPP_EVENT_FAILURE_INVALID_NETWORK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DppFailureStatusCode {
+ }
+
+ /**
+ * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
+ * peer DPP configurator. This callback marks the successful end of the DPP current DPP
+ * session, and no further callbacks will be called. This callback is the successful outcome
+ * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
+ * DppStatusCallback)}.
+ *
+ * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+ */
+ public abstract void onEnrolleeSuccess(int newNetworkId);
+
+ /**
+ * Called when a DPP success event takes place, except for when configuration is received from
+ * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+ * This callback marks the successful end of the current DPP session, and no further
+ * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
+ * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
+ * DppStatusCallback)}.
+ *
+ * @param code DPP success status code.
+ */
+ public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
+
+ /**
+ * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
+ * current DPP session, and no further callbacks will be called.
+ *
+ * @param code DPP failure status code.
+ */
+ public abstract void onFailure(@DppFailureStatusCode int code);
+
+ /**
+ * Called when DPP events that indicate progress take place. Can be used by UI elements
+ * to show progress.
+ *
+ * @param code DPP progress status code.
+ */
+ public abstract void onProgress(@DppProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
new file mode 100644
index 000000000000..c452c7664c12
--- /dev/null
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Interface for DPP callback.
+ *
+ * @hide
+ */
+oneway interface IDppCallback
+{
+ /**
+ * Called when local DPP Enrollee successfully receives a new Wi-Fi configuratrion from the
+ * peer DPP configurator.
+ */
+ void onSuccessConfigReceived(int newNetworkId);
+
+ /**
+ * Called when DPP success events take place, except for when configuration is received from
+ * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+ */
+ void onSuccess(int status);
+
+ /**
+ * Called when DPP Failure events take place.
+ */
+ void onFailure(int status);
+
+ /**
+ * Called when DPP events that indicate progress take place. Can be used by UI elements
+ * to show progress.
+ */
+ void onProgress(int status);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0362a1b491ea..1700006f939d 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@ import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.IDppCallback;
import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ITrafficStateCallback;
@@ -199,5 +200,13 @@ interface IWifiManager
String[] getFactoryMacAddresses();
void setDeviceMobilityState(int state);
+
+ void startDppAsConfiguratorInitiator(in IBinder binder, in String enrolleeUri,
+ int selectedNetworkId, int netRole, in IDppCallback callback);
+
+ void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
+ in IDppCallback callback);
+
+ void stopDppSession();
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index d023b58437af..a809cad74e07 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -28,6 +28,7 @@ import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
import android.net.wifi.WifiInfo;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -632,7 +633,7 @@ public class WifiConfiguration implements Parcelable {
* the network we need to be before autojoin kicks in
*/
/** @hide **/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int INVALID_RSSI = -127;
// States for the userApproved field
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index e5dcef00f001..7cdd16a6a4ed 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -19,6 +19,7 @@ package android.net.wifi;
import android.annotation.UnsupportedAppUsage;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -69,7 +70,7 @@ public class WifiInfo implements Parcelable {
}
private SupplicantState mSupplicantState;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mBSSID;
@UnsupportedAppUsage
private WifiSsid mWifiSsid;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a7c2ff0f875c..e67e8ea7d9ab 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2017,6 +2017,8 @@ public class WifiManager {
public static final int WIFI_FEATURE_OWE = 0x20000000; // Enhanced Open
/** @hide */
public static final int WIFI_FEATURE_LOW_LATENCY = 0x40000000; // Low Latency modes
+ /** @hide */
+ public static final int WIFI_FEATURE_DPP = 0x80000000; // DPP (Easy-Connect)
private int getSupportedFeatures() {
try {
@@ -4463,6 +4465,13 @@ public class WifiManager {
}
/**
+ * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect)
+ */
+ public boolean isDppSupported() {
+ return isFeatureSupported(WIFI_FEATURE_DPP);
+ }
+
+ /**
* Gets the factory Wi-Fi MAC addresses.
* @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
* if failed.
@@ -4541,4 +4550,146 @@ public class WifiManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+
+ /**
+ * DPP Network role: Station.
+ * @hide
+ */
+ @SystemApi
+ public static final int DPP_NETWORK_ROLE_STA = 0;
+
+ /**
+ * DPP Network role: Access Point.
+ * @hide
+ */
+ @SystemApi
+ public static final int DPP_NETWORK_ROLE_AP = 1;
+
+ /** @hide */
+ @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
+ DPP_NETWORK_ROLE_STA,
+ DPP_NETWORK_ROLE_AP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DppNetworkRole {}
+
+ /**
+ * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
+ * with a peer, and configure the peer with the SSID and password of the specified network using
+ * the DPP protocol on an encrypted link.
+ *
+ * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
+ * @param selectedNetworkId Selected network ID to be sent to the peer
+ * @param enrolleeNetworkRole The network role of the enrollee
+ * @param callback Callback for status updates
+ * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD})
+ public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
+ int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
+ @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+ Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
+ enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
+ * with a peer, and receive the SSID and password from the peer configurator.
+ *
+ * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
+ * @param callback Callback for status updates
+ * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD})
+ public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
+ @Nullable Handler handler, @NonNull DppStatusCallback callback) {
+ Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
+ new DppCallbackProxy(looper, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stop or abort a current DPP session.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD})
+ public void stopDppSession() {
+ try {
+ /* Request lower layers to stop/abort and clear resources */
+ mService.stopDppSession();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Helper class to support DPP callbacks
+ * @hide
+ */
+ @SystemApi
+ private static class DppCallbackProxy extends IDppCallback.Stub {
+ private final Handler mHandler;
+ private final DppStatusCallback mDppStatusCallback;
+
+ DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
+ mHandler = new Handler(looper);
+ mDppStatusCallback = dppStatusCallback;
+ }
+
+ @Override
+ public void onSuccessConfigReceived(int newNetworkId) {
+ Log.d(TAG, "DPP onSuccessConfigReceived callback");
+ mHandler.post(() -> {
+ mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+ });
+ }
+
+ @Override
+ public void onSuccess(int status) {
+ Log.d(TAG, "DPP onSuccess callback");
+ mHandler.post(() -> {
+ mDppStatusCallback.onConfiguratorSuccess(status);
+ });
+ }
+
+ @Override
+ public void onFailure(int status) {
+ Log.d(TAG, "DPP onFailure callback");
+ mHandler.post(() -> {
+ mDppStatusCallback.onFailure(status);
+ });
+ }
+
+ @Override
+ public void onProgress(int status) {
+ Log.d(TAG, "DPP onProgress callback");
+ mHandler.post(() -> {
+ mDppStatusCallback.onProgress(status);
+ });
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index 8ae4b5af6325..1603d00fd88a 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -16,6 +16,9 @@
package android.net.wifi.aware;
+import android.os.Parcel;
+import android.os.Parcelable;
+
/**
* Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or
@@ -33,7 +36,7 @@ package android.net.wifi.aware;
* {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter,
* {@link PublishConfig.Builder#setMatchFilter(java.util.List)}.
*/
-public class PeerHandle {
+public final class PeerHandle implements Parcelable {
/** @hide */
public PeerHandle(int peerId) {
this.peerId = peerId;
@@ -59,4 +62,29 @@ public class PeerHandle {
public int hashCode() {
return peerId;
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(peerId);
+ }
+
+ public static final Creator<PeerHandle> CREATOR = new Creator<PeerHandle>() {
+ @Override
+ public PeerHandle[] newArray(int size) {
+ return new PeerHandle[size];
+ }
+
+ @Override
+ public PeerHandle createFromParcel(Parcel in) {
+ int peerHandle = in.readInt();
+
+ return new PeerHandle(peerHandle);
+ }
+ };
+
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 01feb1ef5b42..72e57a16712b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -17,15 +17,15 @@
package android.net.wifi.p2p;
import android.annotation.UnsupportedAppUsage;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import java.util.ArrayList;
-import java.util.List;
import java.util.Collection;
import java.util.Collections;
-import java.util.regex.Pattern;
+import java.util.List;
import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* A class representing a Wi-Fi P2p group. A p2p group consists of a single group
@@ -67,6 +67,9 @@ public class WifiP2pGroup implements Parcelable {
/** The network id in the wpa_supplicant */
private int mNetId;
+ /** The frequency used by this group */
+ private int mFrequency;
+
/** P2P group started string pattern */
private static final Pattern groupStartedPattern = Pattern.compile(
"ssid=\"(.+)\" " +
@@ -116,8 +119,9 @@ public class WifiP2pGroup implements Parcelable {
}
mNetworkName = match.group(1);
- //freq and psk are unused right now
- //int freq = Integer.parseInt(match.group(2));
+ // It throws NumberFormatException if the string cannot be parsed as an integer.
+ mFrequency = Integer.parseInt(match.group(2));
+ // psk is unused right now
//String psk = match.group(3);
mPassphrase = match.group(4);
mOwner = new WifiP2pDevice(match.group(5));
@@ -269,6 +273,16 @@ public class WifiP2pGroup implements Parcelable {
this.mNetId = netId;
}
+ /** Get the operating frequency of the p2p group */
+ public int getFrequency() {
+ return mFrequency;
+ }
+
+ /** @hide */
+ public void setFrequency(int freq) {
+ this.mFrequency = freq;
+ }
+
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("network: ").append(mNetworkName);
@@ -279,6 +293,7 @@ public class WifiP2pGroup implements Parcelable {
}
sbuf.append("\n interface: ").append(mInterface);
sbuf.append("\n networkId: ").append(mNetId);
+ sbuf.append("\n frequency: ").append(mFrequency);
return sbuf.toString();
}
@@ -297,6 +312,7 @@ public class WifiP2pGroup implements Parcelable {
mPassphrase = source.getPassphrase();
mInterface = source.getInterface();
mNetId = source.getNetworkId();
+ mFrequency = source.getFrequency();
}
}
@@ -312,6 +328,7 @@ public class WifiP2pGroup implements Parcelable {
dest.writeString(mPassphrase);
dest.writeString(mInterface);
dest.writeInt(mNetId);
+ dest.writeInt(mFrequency);
}
/** Implement the Parcelable interface */
@@ -329,6 +346,7 @@ public class WifiP2pGroup implements Parcelable {
group.setPassphrase(in.readString());
group.setInterface(in.readString());
group.setNetworkId(in.readInt());
+ group.setFrequency(in.readInt());
return group;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 068b959f14ca..1bed914c7772 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1281,7 +1281,16 @@ public class WifiP2pManager {
c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
}
- /** @hide */
+ /**
+ * Force p2p to enter or exit listen state
+ *
+ * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}
+ * @param enable enables or disables listening
+ * @param listener for callbacks on success or failure. Can be null.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void listen(Channel c, boolean enable, ActionListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index ef1bff4c793c..f9ef08fa6dc1 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -17,6 +17,7 @@
package android.net.wifi.p2p;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcelable;
import android.os.Parcel;
@@ -54,7 +55,7 @@ public class WifiP2pWfdInfo implements Parcelable {
private int mMaxThroughput;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public WifiP2pWfdInfo() {
}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index c9e9867e200d..e32c8e80ad1c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -18,6 +18,7 @@ package android.net.wifi.p2p.nsd;
import android.annotation.UnsupportedAppUsage;
import android.net.nsd.DnsSdTxtRecord;
+import android.os.Build;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -174,7 +175,7 @@ public class WifiP2pDnsSdServiceInfo extends WifiP2pServiceInfo {
* @param version version number
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
static String createRequest(String dnsName, int dnsType, int version) {
StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
index 35631985bdfc..e9ee7bbcaf6c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
@@ -17,6 +17,7 @@
package android.net.wifi.p2p.nsd;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -84,7 +85,7 @@ public class WifiP2pServiceInfo implements Parcelable {
* {"upnp", "10", "uuid:6859dede-8574-59ab-9322-123456789012::urn:schemas-upnp
* -org:service:ContentDirectory:2"}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private List<String> mQueryList;
/**
@@ -93,7 +94,7 @@ public class WifiP2pServiceInfo implements Parcelable {
* @param queryList query string for wpa_supplicant
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected WifiP2pServiceInfo(List<String> queryList) {
if (queryList == null) {
throw new IllegalArgumentException("query list cannot be null");
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
index 2e7f44802ab2..f1f2262b0ec4 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
@@ -18,6 +18,7 @@ package android.net.wifi.p2p.nsd;
import android.annotation.UnsupportedAppUsage;
import android.net.wifi.p2p.WifiP2pManager;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -73,7 +74,7 @@ public class WifiP2pServiceRequest implements Parcelable {
* @param query The part of service specific query.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected WifiP2pServiceRequest(int protocolType, String query) {
validateQuery(query);
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index e882b6bb7c1d..ed38c7613a62 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1382,4 +1382,24 @@ public class WifiAwareManagerTest {
assertEquals(cap.getPeerIpv6Addr().toString(), "/fe80::1322:33ff:fe44:5566%5");
assertEquals(cap.hashCode(), rereadCap.hashCode());
}
+
+ // PeerHandle tests
+
+ @Test
+ public void testPeerHandleParcel() {
+ final PeerHandle peerHandle = new PeerHandle(5);
+
+ Parcel parcelW = Parcel.obtain();
+ peerHandle.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ PeerHandle rereadPeerHandle = PeerHandle.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(peerHandle, rereadPeerHandle);
+ assertEquals(peerHandle.hashCode(), rereadPeerHandle.hashCode());
+ }
}