summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp16
-rw-r--r--Android.mk2
-rwxr-xr-xapi/current.txt102
-rw-r--r--api/system-current.txt69
-rw-r--r--api/test-current.txt4
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h3
-rw-r--r--cmds/statsd/src/StatsService.cpp7
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/atom_field_options.proto14
-rw-r--r--cmds/statsd/src/atoms.proto430
-rw-r--r--cmds/statsd/src/hash.cpp12
-rw-r--r--cmds/statsd/src/main.cpp35
-rw-r--r--cmds/statsd/src/stats_log.proto1
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp26
-rw-r--r--cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java4
-rw-r--r--cmds/statsd/tools/statsd-testdrive/Android.bp11
-rw-r--r--cmds/statsd/tools/statsd-testdrive/manifest.txt1
-rw-r--r--cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java286
-rw-r--r--config/hiddenapi-light-greylist.txt11
-rw-r--r--config/hiddenapi-max-sdk-p-blacklist.txt0
-rw-r--r--core/java/android/accounts/AccountAuthenticatorActivity.java2
-rw-r--r--core/java/android/animation/Keyframe.java6
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityManagerInternal.java7
-rw-r--r--core/java/android/app/ActivityOptions.java2
-rw-r--r--core/java/android/app/ActivityTaskManager.java6
-rw-r--r--core/java/android/app/ActivityThread.java6
-rw-r--r--core/java/android/app/AppDetailsActivity.java36
-rw-r--r--core/java/android/app/AppOpsManager.java17
-rw-r--r--core/java/android/app/ApplicationPackageManager.java14
-rw-r--r--core/java/android/app/ContextImpl.java16
-rw-r--r--core/java/android/app/Fragment.java8
-rw-r--r--core/java/android/app/KeyguardManager.java2
-rw-r--r--core/java/android/app/Notification.java109
-rw-r--r--core/java/android/app/SearchManager.java6
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java68
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/assist/AssistStructure.java185
-rw-r--r--core/java/android/app/backup/BackupAgent.java13
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java20
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java2
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java4
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java4
-rw-r--r--core/java/android/bluetooth/le/AdvertisingSetCallback.java2
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java2
-rw-r--r--core/java/android/content/ClipData.java4
-rw-r--r--core/java/android/content/ContentProviderOperation.java2
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/ContextWrapper.java8
-rw-r--r--core/java/android/content/CursorLoader.java2
-rw-r--r--core/java/android/content/Intent.java8
-rw-r--r--core/java/android/content/IntentFilter.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java8
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java13
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java258
-rw-r--r--core/java/android/content/pm/PackageManager.java70
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java33
-rw-r--r--core/java/android/content/pm/PackageParser.java87
-rw-r--r--core/java/android/content/pm/PackageUserState.java8
-rw-r--r--core/java/android/content/pm/SuspendDialogInfo.aidl18
-rw-r--r--core/java/android/content/pm/SuspendDialogInfo.java379
-rw-r--r--core/java/android/database/sqlite/SQLiteStatement.java2
-rw-r--r--core/java/android/hardware/biometrics/BiometricAuthenticator.java11
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java18
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java19
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl5
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java2
-rw-r--r--core/java/android/hardware/face/FaceManager.java1
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java1
-rw-r--r--core/java/android/hardware/location/ContextHubClient.java2
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java31
-rw-r--r--core/java/android/os/Build.java37
-rw-r--r--core/java/android/os/DumpstateOptions.java57
-rw-r--r--core/java/android/os/GraphicsEnvironment.java71
-rw-r--r--core/java/android/os/IDeviceIdentifiersPolicyService.aidl1
-rw-r--r--core/java/android/os/INetworkManagementService.aidl12
-rw-r--r--core/java/android/os/Message.java12
-rw-r--r--core/java/android/os/UserHandle.java1
-rw-r--r--core/java/android/os/UserManager.java3
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java21
-rw-r--r--core/java/android/permission/PermissionManager.java55
-rw-r--r--core/java/android/provider/Settings.java15
-rw-r--r--core/java/android/service/textclassifier/TextClassifierService.java4
-rw-r--r--core/java/android/text/Layout.java31
-rw-r--r--core/java/android/text/MeasuredParagraph.java35
-rw-r--r--core/java/android/text/NativeMeasuredParagraph.java185
-rw-r--r--core/java/android/text/StaticLayout.java15
-rw-r--r--core/java/android/text/TextUtils.java268
-rw-r--r--core/java/android/text/style/LineBackgroundSpan.java109
-rw-r--r--core/java/android/text/style/TextAppearanceSpan.java29
-rw-r--r--core/java/android/transition/Visibility.java24
-rw-r--r--core/java/android/util/proto/ProtoInputStream.java8
-rw-r--r--core/java/android/view/DisplayCutout.java34
-rw-r--r--core/java/android/view/SurfaceControl.java26
-rw-r--r--core/java/android/view/TouchDelegate.java25
-rw-r--r--core/java/android/view/View.java100
-rw-r--r--core/java/android/view/Window.java17
-rw-r--r--core/java/android/view/WindowManager.java18
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java275
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java11
-rw-r--r--core/java/android/widget/RemoteViews.java67
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/android/widget/Toast.java2
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java105
-rw-r--r--core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java7
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java2
-rw-r--r--core/java/com/android/internal/os/LooperStats.java28
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java1
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java4
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java2
-rw-r--r--core/java/com/android/internal/widget/AlertDialogLayout.java2
-rw-r--r--core/java/com/android/internal/widget/ButtonBarLayout.java2
-rw-r--r--core/java/com/android/internal/widget/DialogTitle.java2
-rw-r--r--core/java/com/android/server/SystemConfig.java8
-rw-r--r--core/jni/Android.bp4
-rw-r--r--core/jni/AndroidRuntime.cpp8
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp25
-rw-r--r--core/jni/android/graphics/text/LineBreaker.cpp (renamed from core/jni/android_text_LineBreaker.cpp)5
-rw-r--r--core/jni/android/graphics/text/MeasuredText.cpp (renamed from core/jni/android_text_MeasuredParagraph.cpp)12
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp5
-rw-r--r--core/jni/android_util_Binder.cpp37
-rw-r--r--core/jni/android_view_SurfaceControl.cpp13
-rw-r--r--core/proto/OWNERS2
-rw-r--r--core/proto/android/internal/powerprofile.proto26
-rw-r--r--core/proto/android/providers/settings/global.proto3
-rw-r--r--core/proto/android/stats/enums.proto (renamed from proto/src/stats_enums.proto)3
-rw-r--r--core/proto/android/telephony/enums.proto61
-rw-r--r--core/res/AndroidManifest.xml26
-rw-r--r--core/res/res/layout/notification_material_media_action.xml2
-rw-r--r--core/res/res/layout/notification_template_material_big_media.xml21
-rw-r--r--core/res/res/layout/notification_template_material_media.xml13
-rw-r--r--core/res/res/values-night/themes_device_defaults.xml4
-rw-r--r--core/res/res/values/config.xml22
-rw-r--r--core/res/res/values/public.xml14
-rw-r--r--core/res/res/values/strings.xml46
-rw-r--r--core/res/res/values/symbols.xml18
-rw-r--r--core/res/res/xml/sms_short_codes.xml11
-rw-r--r--core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java9
-rw-r--r--core/tests/coretests/Android.mk5
-rw-r--r--core/tests/coretests/apks/install_multi_package/Android.mk4
-rw-r--r--core/tests/coretests/apks/install_verifier_bad/Android.mk4
-rw-r--r--core/tests/coretests/apks/install_verifier_good/Android.mk4
-rw-r--r--core/tests/coretests/src/android/app/assist/AssistStructureTest.java30
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java60
-rw-r--r--core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java4
-rw-r--r--core/tests/coretests/src/android/os/FileUtilsTest.java3
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java2
-rw-r--r--core/tests/coretests/src/android/text/MeasuredParagraphTest.java12
-rw-r--r--core/tests/coretests/src/android/text/format/DateUtilsTest.java2
-rw-r--r--core/tests/coretests/src/android/view/DisplayCutoutTest.java12
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java68
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk2
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk2
-rw-r--r--core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk2
-rw-r--r--core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk2
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java2
-rw-r--r--graphics/java/android/graphics/BaseRecordingCanvas.java2
-rw-r--r--graphics/java/android/graphics/Bitmap.java46
-rw-r--r--graphics/java/android/graphics/ColorSpace.java10
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java3
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java1
-rw-r--r--graphics/java/android/graphics/text/LineBreaker.java (renamed from core/java/android/text/NativeLineBreaker.java)183
-rw-r--r--graphics/java/android/graphics/text/MeasuredText.java289
-rw-r--r--keystore/OWNERS4
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/androidfw/ApkAssets.cpp2
-rw-r--r--libs/androidfw/AssetManager2.cpp8
-rw-r--r--libs/androidfw/LoadedArsc.cpp34
-rw-r--r--libs/androidfw/PosixUtils.cpp112
-rw-r--r--libs/androidfw/include/androidfw/ApkAssets.h7
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h9
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h50
-rw-r--r--libs/androidfw/include/androidfw/PosixUtils.h36
-rw-r--r--libs/androidfw/include/androidfw/ZipFileRO.h3
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp48
-rw-r--r--libs/androidfw/tests/PosixUtils_test.cpp55
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/JankTracker.cpp2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp13
-rw-r--r--libs/hwui/hwui/Bitmap.h2
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.h4
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaUtils.h28
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp17
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp9
-rw-r--r--location/java/android/location/LocationManager.java4
-rw-r--r--media/java/android/media/ExifInterface.java6
-rw-r--r--media/java/android/media/MediaCrypto.java12
-rw-r--r--media/java/android/media/MediaDrm.java1
-rw-r--r--media/java/android/media/MediaPlayer2.java121
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java1066
-rw-r--r--media/java/android/media/update/ApiLoader.java54
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp21
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java1
-rw-r--r--packages/CtsShim/build/Android.mk8
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt13
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/Painting.kt35
-rw-r--r--packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt22
-rw-r--r--packages/PackageInstaller/AndroidManifest.xml1
-rw-r--r--packages/PackageInstaller/res/values/strings.xml10
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java347
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java42
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java4
-rw-r--r--packages/PrintSpooler/Android.bp38
-rw-r--r--packages/PrintSpooler/Android.mk45
-rw-r--r--packages/PrintSpooler/tests/Android.mk19
-rw-r--r--packages/PrintSpooler/tests/outofprocess/Android.bp30
-rw-r--r--packages/PrintSpooler/tests/outofprocess/Android.mk30
-rw-r--r--packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java12
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml4
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java53
-rw-r--r--packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml7
-rw-r--r--packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java2
-rw-r--r--packages/SettingsLib/res/layout/restricted_switch_widget.xml4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java50
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java91
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml11
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java28
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java146
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java346
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java149
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java13
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto15
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java10
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java7
-rw-r--r--services/art-profile8
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java47
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java199
-rw-r--r--services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java4
-rw-r--r--services/backup/java/com/android/server/backup/Trampoline.java84
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java13
-rw-r--r--services/core/Android.bp3
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java86
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java66
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java24
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java264
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java38
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java5
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java7
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java16
-rw-r--r--services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java65
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java49
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java288
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java59
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java86
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java91
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java117
-rw-r--r--services/core/java/com/android/server/am/ActivityStartController.java14
-rw-r--r--services/core/java/com/android/server/am/ActivityStartInterceptor.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java151
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java91
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java211
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java4
-rw-r--r--services/core/java/com/android/server/am/CompatModePackages.java21
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java5
-rw-r--r--services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java6
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java6
-rw-r--r--services/core/java/com/android/server/am/LaunchParamsController.java66
-rw-r--r--services/core/java/com/android/server/am/LockTaskController.java10
-rw-r--r--services/core/java/com/android/server/am/MemoryStatUtil.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java53
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java132
-rw-r--r--services/core/java/com/android/server/am/RecentTasks.java18
-rw-r--r--services/core/java/com/android/server/am/SafeActivityOptions.java8
-rw-r--r--services/core/java/com/android/server/am/TaskLaunchParamsModifier.java870
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java24
-rw-r--r--services/core/java/com/android/server/am/VrController.java4
-rw-r--r--services/core/java/com/android/server/am/WindowProcessController.java126
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationClient.java11
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java28
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricServiceBase.java26
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java5
-rw-r--r--services/core/java/com/android/server/connectivity/ProxyTracker.java108
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java23
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java22
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientBroker.java65
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java16
-rw-r--r--services/core/java/com/android/server/media/MediaUpdateService.java65
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java18
-rw-r--r--services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java32
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java79
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java102
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java9
-rw-r--r--services/core/java/com/android/server/pm/Settings.java38
-rw-r--r--services/core/java/com/android/server/pm/dex/TEST_MAPPING19
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java4
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java13
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java20
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java5
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java34
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java15
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/net/java/android/net/ip/IpNeighborMonitor.java1
-rw-r--r--services/net/java/android/net/ip/RouterAdvertisementDaemon.java1
-rw-r--r--services/net/java/android/net/netlink/NetlinkSocket.java1
-rw-r--r--services/robotests/Android.mk4
-rw-r--r--services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java50
-rw-r--r--services/tests/mockingservicestests/Android.mk1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java248
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java144
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java1189
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java116
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java58
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java90
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java6
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java70
-rw-r--r--startop/tools/view_compiler/Android.bp19
-rw-r--r--startop/tools/view_compiler/dex_builder.cc214
-rw-r--r--startop/tools/view_compiler/dex_builder.h189
-rw-r--r--startop/tools/view_compiler/dex_builder_test.cc82
-rw-r--r--startop/tools/view_compiler/main.cc15
-rw-r--r--telecomm/java/android/telecom/Call.java14
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java2
-rw-r--r--telephony/java/android/provider/Telephony.java1
-rw-r--r--telephony/java/android/telephony/NeighboringCellInfo.java4
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationState.java44
-rw-r--r--telephony/java/android/telephony/ServiceState.java173
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java93
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java176
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java4
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java183
-rw-r--r--test-mock/api/system-current.txt1
-rw-r--r--test-mock/src/android/test/mock/MockContext.java6
-rw-r--r--tests/ActivityTests/Android.mk4
-rw-r--r--tests/NetworkSecurityConfigTest/Android.mk1
-rw-r--r--tests/net/Android.mk6
-rw-r--r--tools/aapt2/Main.cpp28
-rw-r--r--tools/aapt2/OWNERS1
-rw-r--r--tools/aapt2/cmd/Command.cpp16
-rw-r--r--tools/aapt2/cmd/Command.h3
-rw-r--r--tools/aapt2/cmd/Convert.cpp22
-rw-r--r--tools/aapt2/cmd/Dump.cpp446
-rw-r--r--tools/aapt2/cmd/Dump.h249
-rw-r--r--tools/aapt2/cmd/Link.cpp10
-rw-r--r--tools/aapt2/cmd/Link.h6
-rw-r--r--tools/aapt2/dump/DumpManifest.cpp353
-rw-r--r--tools/aapt2/dump/DumpManifest.h46
-rwxr-xr-xtools/hiddenapi/sort_api.sh4
-rw-r--r--tools/stats_log_api_gen/Collation.cpp4
-rw-r--r--tools/stats_log_api_gen/test.proto24
-rw-r--r--wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java163
-rw-r--r--wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java11
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java3
436 files changed, 12954 insertions, 6082 deletions
diff --git a/Android.bp b/Android.bp
index 7e71bdfe35c7..f9b60e67e659 100644
--- a/Android.bp
+++ b/Android.bp
@@ -614,6 +614,7 @@ java_defaults {
":netd_aidl",
":vold_aidl",
":installd_aidl",
+ ":dumpstate_aidl",
"lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
"lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
@@ -660,6 +661,7 @@ java_defaults {
include_dirs: [
"system/update_engine/binder_bindings",
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"frameworks/av/camera/aidl",
"frameworks/av/media/libaudioclient/aidl",
"frameworks/native/aidl/gui",
@@ -682,9 +684,6 @@ java_defaults {
no_framework_libs: true,
libs: [
- "conscrypt",
- "okhttp",
- "bouncycastle",
"ext",
],
@@ -706,6 +705,7 @@ java_defaults {
"android.hardware.radio-V1.0-java",
"android.hardware.radio-V1.3-java",
"android.hardware.usb.gadget-V1.0-java",
+ "netd_aidl_interface-java",
],
// Loaded with System.loadLibrary by android.view.textclassifier
@@ -835,7 +835,6 @@ java_library_host {
"cmds/statsd/src/**/*.proto",
"core/proto/**/*.proto",
"libs/incident/proto/**/*.proto",
- "proto/src/stats_enums.proto",
],
proto: {
include_dirs: ["external/protobuf/src"],
@@ -873,7 +872,6 @@ java_library {
srcs: [
"core/proto/**/*.proto",
"libs/incident/proto/android/os/**/*.proto",
- "proto/src/stats_enums.proto",
],
// Protos have lots of MissingOverride and similar.
errorprone: {
@@ -899,7 +897,6 @@ cc_library {
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- "proto/src/stats_enums.proto",
],
target: {
@@ -1096,14 +1093,13 @@ framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xm
"-federationapi SupportLib $(location current/support-api.txt) "
framework_docs_only_args = " -android -manifest $(location core/res/AndroidManifest.xml) " +
+ "-werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 " +
"-overview $(location core/java/overview.html) " +
// Federate Support Library references against local API file.
"-federate SupportLib https://developer.android.com " +
"-federationapi SupportLib $(location current/support-api.txt) "
framework_docs_only_libs = [
- "conscrypt",
- "bouncycastle",
"voip-common",
"android.test.mock",
"android-support-annotations",
@@ -1183,7 +1179,8 @@ stubs_defaults {
doc_defaults {
name: "framework-docs-default",
- libs: framework_docs_only_libs,
+ libs: framework_docs_only_libs +
+ ["stub-annotations"],
html_dirs: [
"docs/html",
],
@@ -1580,7 +1577,6 @@ filegroup {
"core/java/org/apache/http/params/CoreConnectionPNames.java",
"core/java/org/apache/http/params/HttpConnectionParams.java",
"core/java/org/apache/http/params/HttpParams.java",
- "core/java/android/net/http/HttpResponseCache.java",
"core/java/android/net/http/SslCertificate.java",
"core/java/android/net/http/SslError.java",
"core/java/com/android/internal/util/HexDump.java",
diff --git a/Android.mk b/Android.mk
index d33307425968..ba153ee76b0a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -87,6 +87,7 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
+ frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
frameworks/base/config/hiddenapi-force-blacklist.txt \
$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
@@ -98,6 +99,7 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
--input-greylists \
frameworks/base/config/hiddenapi-light-greylist.txt \
frameworks/base/config/hiddenapi-vendor-list.txt \
+ frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
<(comm -12 <(sort $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST)) \
$(PRIVATE_GREYLIST_INPUTS) \
diff --git a/api/current.txt b/api/current.txt
index 2a2f204d5ac0..0ffa38b6360a 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -17,6 +17,7 @@ package android {
field public static final java.lang.String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+ field public static final java.lang.String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
@@ -168,6 +169,7 @@ package android {
public static final class Manifest.permission_group {
ctor public Manifest.permission_group();
+ field public static final java.lang.String ACTIVITY_RECOGNITION = "android.permission-group.ACTIVITY_RECOGNITION";
field public static final java.lang.String CALENDAR = "android.permission-group.CALENDAR";
field public static final java.lang.String CALL_LOG = "android.permission-group.CALL_LOG";
field public static final java.lang.String CAMERA = "android.permission-group.CAMERA";
@@ -13262,6 +13264,7 @@ package android.graphics {
method public void setPixels(int[], int, int, int, int, int, int);
method public void setPremultiplied(boolean);
method public void setWidth(int);
+ method public static android.graphics.Bitmap wrapHardwareBuffer(android.hardware.HardwareBuffer, android.graphics.ColorSpace);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR;
field public static final int DENSITY_NONE = 0; // 0x0
@@ -15404,6 +15407,69 @@ package android.graphics.pdf {
}
+package android.graphics.text {
+
+ public class LineBreaker {
+ method public android.graphics.text.LineBreaker.Result computeLineBreaks(android.graphics.text.MeasuredText, android.graphics.text.LineBreaker.ParagraphConstraints, int);
+ field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+ field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+ field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
+ field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
+ field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
+ field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
+ field public static final int JUSTIFICATION_MODE_INTER_WORD = 1; // 0x1
+ field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
+ }
+
+ public static class LineBreaker.Builder {
+ ctor public LineBreaker.Builder();
+ method public android.graphics.text.LineBreaker build();
+ method public android.graphics.text.LineBreaker.Builder setBreakStrategy(int);
+ method public android.graphics.text.LineBreaker.Builder setHyphenationFrequency(int);
+ method public android.graphics.text.LineBreaker.Builder setIndents(int[]);
+ method public android.graphics.text.LineBreaker.Builder setJustified(int);
+ }
+
+ public static class LineBreaker.ParagraphConstraints {
+ ctor public LineBreaker.ParagraphConstraints();
+ method public int getDefaultTabStop();
+ method public float getFirstWidth();
+ method public int getFirstWidthLineCount();
+ method public int[] getTabStops();
+ method public float getWidth();
+ method public void setIndent(float, int);
+ method public void setTabStops(int[], int);
+ method public void setWidth(float);
+ }
+
+ public static class LineBreaker.Result {
+ method public float getLineAscent(int);
+ method public int getLineBreakOffset(int);
+ method public int getLineCount();
+ method public float getLineDescent(int);
+ method public int getLineHyphenEdit(int);
+ method public float getLineWidth(int);
+ method public boolean hasLineTab(int);
+ }
+
+ public class MeasuredText {
+ method public void getBounds(int, int, android.graphics.Rect);
+ method public float getCharWidthAt(int);
+ method public char[] getChars();
+ method public float getWidth(int, int);
+ }
+
+ public static class MeasuredText.Builder {
+ ctor public MeasuredText.Builder(char[]);
+ method public android.graphics.text.MeasuredText.Builder addReplacementRun(android.graphics.Paint, int, int, float);
+ method public android.graphics.text.MeasuredText.Builder addStyleRun(android.graphics.Paint, int, int, boolean);
+ method public android.graphics.text.MeasuredText build();
+ method public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
+ method public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
+ }
+
+}
+
package android.hardware {
public deprecated class Camera {
@@ -32539,7 +32605,7 @@ package android.os {
public class Build {
ctor public Build();
- method public static java.util.List<android.os.Build.Partition> getPartitions();
+ method public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
method public static java.lang.String getRadioVersion();
method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
@@ -32570,9 +32636,9 @@ package android.os {
public static class Build.Partition {
ctor public Build.Partition();
+ method public long getBuildTimeMillis();
method public java.lang.String getFingerprint();
method public java.lang.String getName();
- method public long getTimeMillis();
field public static final java.lang.String PARTITION_NAME_SYSTEM = "system";
}
@@ -42967,7 +43033,6 @@ package android.telephony {
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
- method public static int getSlotIndex(int);
method public static int[] getSubscriptionIds(int);
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
method public boolean isActiveSubscriptionId(int);
@@ -42988,9 +43053,7 @@ package android.telephony {
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
- field public static final int INVALID_SIM_SLOT_INDEX = -2; // 0xfffffffe
field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
- field public static final int SIM_NOT_INSERTED = -3; // 0xfffffffd
}
public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
@@ -43325,7 +43388,7 @@ package android.telephony.data {
field public static final int PROTOCOL_IPV6 = 1; // 0x1
field public static final int PROTOCOL_PPP = 3; // 0x3
field public static final int TYPE_CBS = 128; // 0x80
- field public static final int TYPE_DEFAULT = 1; // 0x1
+ field public static final int TYPE_DEFAULT = 17; // 0x11
field public static final int TYPE_DUN = 8; // 0x8
field public static final int TYPE_EMERGENCY = 512; // 0x200
field public static final int TYPE_FOTA = 32; // 0x20
@@ -44321,6 +44384,7 @@ package android.text {
method public static int lastIndexOf(java.lang.CharSequence, char, int);
method public static int lastIndexOf(java.lang.CharSequence, char, int, int);
method public static java.lang.CharSequence listEllipsize(android.content.Context, java.util.List<java.lang.CharSequence>, java.lang.String, android.text.TextPaint, float, int);
+ method public static java.lang.CharSequence makeSafeForPresentation(java.lang.String, int, float, int);
method public static boolean regionMatches(java.lang.CharSequence, int, java.lang.CharSequence, int, int);
method public static java.lang.CharSequence replace(java.lang.CharSequence, java.lang.String[], java.lang.CharSequence[]);
method public static java.lang.String[] split(java.lang.String, java.lang.String);
@@ -44332,6 +44396,9 @@ package android.text {
field public static final int CAP_MODE_SENTENCES = 16384; // 0x4000
field public static final int CAP_MODE_WORDS = 8192; // 0x2000
field public static final android.os.Parcelable.Creator<java.lang.CharSequence> CHAR_SEQUENCE_CREATOR;
+ field public static final int SAFE_STRING_FLAG_FIRST_LINE = 4; // 0x4
+ field public static final int SAFE_STRING_FLAG_SINGLE_LINE = 2; // 0x2
+ field public static final int SAFE_STRING_FLAG_TRIM = 1; // 0x1
}
public static abstract interface TextUtils.EllipsizeCallback {
@@ -44930,6 +44997,16 @@ package android.text.style {
method public abstract void drawBackground(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, int);
}
+ public static class LineBackgroundSpan.Standard implements android.text.style.LineBackgroundSpan android.text.ParcelableSpan {
+ ctor public LineBackgroundSpan.Standard(int);
+ ctor public LineBackgroundSpan.Standard(android.os.Parcel);
+ method public int describeContents();
+ method public void drawBackground(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, int);
+ method public final int getColor();
+ method public int getSpanTypeId();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public abstract interface LineHeightSpan implements android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan {
method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
}
@@ -48027,6 +48104,7 @@ package android.view {
public class TouchDelegate {
ctor public TouchDelegate(android.graphics.Rect, android.view.View);
+ method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
method public boolean onTouchEvent(android.view.MotionEvent);
field public static final int ABOVE = 1; // 0x1
field public static final int BELOW = 2; // 0x2
@@ -50009,6 +50087,7 @@ package android.view.accessibility {
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
method public java.lang.CharSequence getTooltipText();
+ method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
method public java.lang.String getViewIdResourceName();
@@ -50099,6 +50178,7 @@ package android.view.accessibility {
method public void setTextEntryKey(boolean);
method public void setTextSelection(int, int);
method public void setTooltipText(java.lang.CharSequence);
+ method public void setTouchDelegateInfo(android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
method public void setTraversalAfter(android.view.View);
method public void setTraversalAfter(android.view.View, int);
method public void setTraversalBefore(android.view.View);
@@ -50225,6 +50305,16 @@ package android.view.accessibility {
field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
}
+ public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+ ctor public AccessibilityNodeInfo.TouchDelegateInfo(java.util.Map<android.graphics.Region, android.view.View>);
+ method public int describeContents();
+ method public android.graphics.Region getRegionAt(int);
+ method public int getRegionCount();
+ method public android.view.accessibility.AccessibilityNodeInfo getTargetForRegion(android.graphics.Region);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo> CREATOR;
+ }
+
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index 30a0c850f865..eccc0ea0592a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -119,6 +119,7 @@ package android {
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+ field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -221,7 +222,7 @@ package android {
}
public static final class R.dimen {
- field public static final int config_restricted_icon_size = 17104903; // 0x1050007
+ field public static final int config_restrictedIconSize = 17104903; // 0x1050007
}
public static final class R.drawable {
@@ -234,12 +235,12 @@ package android {
}
public static final class R.string {
- field public static final int config_feedback_intent_extra_key = 17039391; // 0x104001f
- field public static final int config_feedback_intent_name_key = 17039392; // 0x1040020
- field public static final int config_help_intent_extra_key = 17039389; // 0x104001d
- field public static final int config_help_intent_name_key = 17039390; // 0x104001e
- field public static final int config_help_package_name_key = 17039387; // 0x104001b
- field public static final int config_help_package_name_value = 17039388; // 0x104001c
+ field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
+ field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020
+ field public static final int config_helpIntentExtraKey = 17039389; // 0x104001d
+ field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
+ field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
+ field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
}
public static final class R.style {
@@ -523,11 +524,11 @@ package android.app.admin {
method public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
method public java.lang.String getDeviceOwnerNameOnAnyUser();
method public java.lang.CharSequence getDeviceOwnerOrganizationName();
- method public int getDeviceOwnerUserId();
+ method public android.os.UserHandle getDeviceOwnerUser();
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
- method public android.content.ComponentName getProfileOwnerAsUser(int);
+ method public android.content.ComponentName getProfileOwnerAsUser(android.os.UserHandle);
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public int getUserProvisioningState();
method public boolean isDeviceManaged();
@@ -1121,9 +1122,9 @@ package android.content.pm {
method public static void forceSafeLabels();
method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
- field public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
- field public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
- field public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
+ field public static final deprecated int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
+ field public static final deprecated int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
+ field public static final deprecated int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
}
public abstract class PackageManager {
@@ -1150,7 +1151,8 @@ package android.content.pm {
method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
- method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
+ method public deprecated java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
+ method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo);
method public abstract void setUpdateAvailable(java.lang.String, boolean);
method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
@@ -1244,6 +1246,22 @@ package android.content.pm {
field public int requestRes;
}
+ public final class SuspendDialogInfo 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.pm.SuspendDialogInfo> CREATOR;
+ }
+
+ public static final class SuspendDialogInfo.Builder {
+ ctor public SuspendDialogInfo.Builder();
+ method public android.content.pm.SuspendDialogInfo build();
+ method public android.content.pm.SuspendDialogInfo.Builder setIcon(int);
+ method public android.content.pm.SuspendDialogInfo.Builder setMessage(java.lang.String);
+ method public android.content.pm.SuspendDialogInfo.Builder setMessage(int);
+ method public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(int);
+ method public android.content.pm.SuspendDialogInfo.Builder setTitle(int);
+ }
+
}
package android.content.pm.dex {
@@ -1280,14 +1298,6 @@ package android.content.pm.permission {
}
-package android.graphics.drawable {
-
- public final class Icon implements android.os.Parcelable {
- method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
- }
-
-}
-
package android.hardware {
public final class Sensor {
@@ -3189,6 +3199,7 @@ package android.net {
public class ConnectivityManager {
method public java.lang.String getCaptivePortalServerUrl();
method public boolean isTetheringSupported();
+ method public void setAirplaneMode(boolean);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method public void stopTethering(int);
@@ -4132,12 +4143,10 @@ package android.os {
field public static final android.os.UserHandle ALL;
field public static final android.os.UserHandle CURRENT;
field public static final android.os.UserHandle SYSTEM;
- field public static final int USER_NULL = -10000; // 0xffffd8f0
}
public class UserManager {
method public void clearSeedAccountData();
- method public int[] getProfileIds(int, boolean);
method public java.lang.String getSeedAccountName();
method public android.os.PersistableBundle getSeedAccountOptions();
method public java.lang.String getSeedAccountType();
@@ -4202,8 +4211,8 @@ package android.permission {
}
public static final class PermissionManager.SplitPermissionInfo {
- method public java.lang.String[] getNewPermissions();
- method public java.lang.String getRootPermission();
+ method public java.util.List<java.lang.String> getNewPermissions();
+ method public java.lang.String getSplitPermission();
method public int getTargetSdk();
}
@@ -5288,6 +5297,7 @@ package android.telephony {
method public int getRejectCause();
method public int getTransportType();
method public boolean isEmergencyEnabled();
+ method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
field public static final int DOMAIN_CS = 1; // 0x1
@@ -5375,6 +5385,8 @@ package android.telephony {
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+ field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
}
public final class SubscriptionPlan implements android.os.Parcelable {
@@ -6654,7 +6666,7 @@ package android.util {
package android.view {
public abstract class Window {
- method public void addPrivateFlags(int);
+ method public void addSystemFlags(int);
}
public abstract interface WindowManager implements android.view.ViewManager {
@@ -6664,7 +6676,10 @@ package android.view {
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
method public final long getUserActivityTimeout();
method public final void setUserActivityTimeout(long);
- field public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
+ field public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
+ }
+
+ public static abstract class WindowManager.LayoutParams.SystemFlags implements java.lang.annotation.Annotation {
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 937c2660ec0a..463c9d358985 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1609,6 +1609,10 @@ package android.view.accessibility {
method public void writeToParcelNoRecycle(android.os.Parcel, int);
}
+ public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+ method public long getAccessibilityIdForRegion(android.graphics.Region);
+ }
+
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 4091d951ba06..6a9e8a1bf688 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -39,7 +39,8 @@ enum DumpReportReason {
GET_DATA_CALLED = 4,
ADB_DUMP = 5,
CONFIG_RESET = 6,
- STATSCOMPANION_DIED = 7
+ STATSCOMPANION_DIED = 7,
+ TERMINATION_SIGNAL_RECEIVED = 8
};
class StatsLogProcessor : public ConfigListener {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8da2d447a163..fb6f8c8d4590 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -867,6 +867,13 @@ void StatsService::Startup() {
mConfigManager->Startup();
}
+void StatsService::Terminate() {
+ ALOGI("StatsService::Terminating");
+ if (mProcessor != nullptr) {
+ mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED);
+ }
+}
+
void StatsService::OnLogEvent(LogEvent* event) {
mProcessor->OnLogEvent(event);
if (mShellSubscriber != nullptr) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 1f1d782af235..cbf34292c1d4 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -84,6 +84,11 @@ public:
void Startup();
/**
+ * Called when terminiation signal received.
+ */
+ void Terminate();
+
+ /**
* Called by LogReader when there's a log event to process.
*/
virtual void OnLogEvent(LogEvent* event);
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index a2a03b14c073..453bf7e126cd 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -36,8 +36,8 @@ enum StateField {
// exclusive state field, and any number of primary key fields.
// For example,
// message UidProcessStateChanged {
-// optional int32 uid = 1 [(stateFieldOption).option = PRIMARY];
-// optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE];
+// optional int32 uid = 1 [(state_field_option).option = PRIMARY];
+// optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
// }
// Each of this UidProcessStateChanged atom represents a state change for a specific uid.
// A new state automatically overrides the previous state.
@@ -46,16 +46,16 @@ enum StateField {
// the primary key.
// For example:
// message ThreadStateChanged {
-// optional int32 pid = 1 [(stateFieldOption).option = PRIMARY];
-// optional int32 tid = 2 [(stateFieldOption).option = PRIMARY];
-// optional int32 state = 3 [(stateFieldOption).option = EXCLUSIVE];
+// optional int32 pid = 1 [(state_field_option).option = PRIMARY];
+// optional int32 tid = 2 [(state_field_option).option = PRIMARY];
+// optional int32 state = 3 [(state_field_option).option = EXCLUSIVE];
// }
//
// Sometimes, there is no primary key field, when the state is GLOBAL.
// For example,
//
// message ScreenStateChanged {
-// optional android.view.DisplayStateEnum state = 1 [(stateFieldOption).option = EXCLUSIVE];
+// optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
// }
//
// Only fields of primary types can be annotated. AttributionNode cannot be primary keys (and they
@@ -66,7 +66,7 @@ message StateAtomFieldOption {
extend google.protobuf.FieldOptions {
// Flags to decorate an atom that presents a state change.
- optional StateAtomFieldOption stateFieldOption = 50000;
+ optional StateAtomFieldOption state_field_option = 50000;
// Flags to decorate the uid fields in an atom.
optional bool is_uid = 50001 [default = false];
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9d83afdeb819..46045101f168 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -26,12 +26,11 @@ import "frameworks/base/core/proto/android/app/job/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/enums.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/service/procstats_enum.proto";
+import "frameworks/base/core/proto/android/stats/enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/proto/src/stats_enums.proto";
-import "frameworks/base/core/proto/android/service/procstats.proto";
-import "frameworks/base/core/proto/android/internal/powerprofile.proto";
/**
* The master atom class. This message defines all of the available
@@ -142,6 +141,8 @@ message Atom {
BatteryHealthSnapshot battery_health_snapshot = 91;
SlowIo slow_io = 92;
BatteryCausedShutdown battery_caused_shutdown = 93;
+ PhoneServiceStateChanged phone_service_state_changed = 94;
+ PhoneStateChanged phone_state_changed = 95;
}
// Pulled events will start at field 10000.
@@ -273,7 +274,7 @@ message ThermalThrottlingStateChanged {
*/
message ScreenStateChanged {
// New screen state, from frameworks/base/core/proto/android/view/enums.proto.
- optional android.view.DisplayStateEnum state = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional android.view.DisplayStateEnum state = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -284,10 +285,10 @@ message ScreenStateChanged {
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
message UidProcessStateChanged {
- optional int32 uid = 1 [(stateFieldOption).option = PRIMARY, (is_uid) = true];
+ optional int32 uid = 1 [(state_field_option).option = PRIMARY, (is_uid) = true];
// The state, from frameworks/base/core/proto/android/app/enums.proto.
- optional android.app.ProcessStateEnum state = 2 [(stateFieldOption).option = EXCLUSIVE];
+ optional android.app.ProcessStateEnum state = 2 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -319,7 +320,7 @@ message ActivityManagerSleepStateChanged {
ASLEEP = 1;
AWAKE = 2;
}
- optional State state = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional State state = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -338,7 +339,7 @@ message MemoryFactorStateChanged {
CRITICAL = 4; // critical memory.
}
- optional State factor = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional State factor = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -637,7 +638,7 @@ message WakelockStateChanged {
// The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock.
// From frameworks/base/core/proto/android/os/enums.proto.
- optional android.os.WakeLockLevelEnum level = 2;
+ optional android.os.WakeLockLevelEnum type = 2;
// The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
optional string tag = 3;
@@ -1030,20 +1031,20 @@ message ResourceConfigurationChanged {
// Bit mask of color capabilities of the screen.
// Contains information about the color gamut and hdr mode of the screen.
// See: https://d.android.com/reference/android/content/res/Configuration.html#colorMode
- optional int32 colorMode = 1;
+ optional int32 color_mode = 1;
// The target screen density being rendered to.
// See: https://d.android.com/reference/android/content/res/Configuration.html#densityDpi
- optional int32 densityDpi = 2;
+ optional int32 density_dpi = 2;
// Current user preference for the scaling factor for fonts,
// relative to the base density scaling.
// See: https://d.android.com/reference/android/content/res/Configuration.html#fontScale
- optional float fontScale = 3;
+ optional float font_scale = 3;
// Flag indicating whether the hard keyboard is hidden.
// See: https://d.android.com/reference/android/content/res/Configuration.html#hardKeyboardHidden
- optional int32 hardKeyboardHidden = 4;
+ optional int32 hard_keyboard_hidden = 4;
// The type of keyboard attached to the device.
// See: https://d.android.com/reference/android/content/res/Configuration.html#keyboard
@@ -1051,7 +1052,7 @@ message ResourceConfigurationChanged {
// Flag indicating whether any keyboard is available. Takes soft keyboards into account.
// See: https://d.android.com/reference/android/content/res/Configuration.html#keyboardHidden
- optional int32 keyboardHideen = 6;
+ optional int32 keyboard_hidden = 6;
// IMSI MCC (Mobile Country Code), corresponding to mcc resource qualifier.
// 0 if undefined.
@@ -1070,7 +1071,7 @@ message ResourceConfigurationChanged {
// Flag indicating whether the navigation is available.
// See: https://d.android.com/reference/android/content/res/Configuration.html#navigationHidden
- optional int32 navigationHidden = 10;
+ optional int32 navigation_hidden = 10;
// Overall orientation of the screen.
// See: https://d.android.com/reference/android/content/res/Configuration.html#orientation
@@ -1078,24 +1079,24 @@ message ResourceConfigurationChanged {
// The current height of the available screen space, in dp units.
// See: https://d.android.com/reference/android/content/res/Configuration.html#screenHeightDp
- optional int32 screenHeightDp = 12;
+ optional int32 screen_height_dp = 12;
// Bit mask of overall layout of the screen.
// Contains information about screen size, whether the screen is wider/taller
// than normal, whether the screen layout is right-tl-left or left-to-right,
// and whether the screen has a rounded shape.
// See: https://d.android.com/reference/android/content/res/Configuration.html#screenLayout
- optional int32 screenLayout = 13;
+ optional int32 screen_layout = 13;
// Current width of the available screen space, in dp units.
// See: https://d.android.com/reference/android/content/res/Configuration.html#screenWidthDp
- optional int32 screenWidthDp = 14;
+ optional int32 screen_width_dp = 14;
// The smallest screen size an application will see in normal operation.
// This is the smallest value of both screenWidthDp and screenHeightDp
// in portrait and landscape.
// See: https://d.android.com/reference/android/content/res/Configuration.html#smallestScreenWidthDp
- optional int32 smallestScreenWidthDp = 15;
+ optional int32 smallest_screen_width_dp = 15;
// The type of touch screen attached to the device.
// See: https://d.android.com/reference/android/content/res/Configuration.html#touchscreen
@@ -1106,7 +1107,7 @@ message ResourceConfigurationChanged {
// Eg: NORMAL, DESK, CAR, TELEVISION, WATCH, VR_HEADSET
// Also contains information about whether the device is in night mode.
// See: https://d.android.com/reference/android/content/res/Configuration.html#uiMode
- optional int32 uiMode = 17;
+ optional int32 ui_mode = 17;
}
@@ -1193,7 +1194,7 @@ message BluetoothEnabledStateChanged {
// Eg. Airplane mode, crash, application request.
optional android.bluetooth.EnableDisableReasonEnum reason = 3;
// If the reason is an application request, this will be the package name.
- optional string pkgName = 4;
+ optional string pkg_name = 4;
}
/**
@@ -1342,7 +1343,7 @@ message BatteryHealthSnapshot {
}
optional BatterySnapshotType type = 1;
// Temperature, in 1/10ths of degree C.
- optional int32 temperature_deci_celcius = 2;
+ optional int32 temperature_deci_celsius = 2;
// Voltage Battery Voltage, in microVolts.
optional int32 voltage_micro_volt = 3;
// Current Battery current, in microAmps.
@@ -1406,6 +1407,33 @@ message PhoneSignalStrengthChanged {
optional android.telephony.SignalStrengthEnum signal_strength = 1;
}
+
+/**
+ * Logs when the phone state, sim state or signal strength changes
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PhoneServiceStateChanged {
+ optional android.telephony.ServiceStateEnum state = 1;
+ optional android.telephony.SimStateEnum sim_state = 2;
+ optional android.telephony.SignalStrengthEnum signal_strength = 3;
+}
+
+/**
+ * Logs when the phone becomes on or off.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/TelephonyRegistry.java
+ */
+message PhoneStateChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
/**
* Logs that a setting was updated.
* Logged from:
@@ -1843,10 +1871,10 @@ message AppStartMemoryStateCaptured {
optional string activity_name = 3;
// # of page-faults
- optional int64 pgfault = 4;
+ optional int64 page_fault = 4;
// # of major page-faults
- optional int64 pgmajfault = 5;
+ optional int64 page_major_fault = 5;
// RSS
optional int64 rss_in_bytes = 6;
@@ -1886,13 +1914,13 @@ message LmkKillOccurred {
optional string process_name = 2;
// oom adj score.
- optional int32 oom_score = 3;
+ optional int32 oom_adj_score = 3;
// # of page-faults
- optional int64 pgfault = 4;
+ optional int64 page_fault = 4;
// # of major page-faults
- optional int64 pgmajfault = 5;
+ optional int64 page_major_fault = 5;
// RSS
optional int64 rss_in_bytes = 6;
@@ -1912,7 +1940,7 @@ message LmkKillOccurred {
*/
message AppDied {
// timestamp(elapsedRealtime) of record creation
- optional uint64 timestamp_millis = 1 [(stateFieldOption).option = EXCLUSIVE];
+ optional uint64 timestamp_millis = 1 [(state_field_option).option = EXCLUSIVE];
}
/**
@@ -1923,7 +1951,7 @@ message GenericAtom {
optional int32 uid = 1 [(is_uid) = true];
// An event_id indicates the type of event.
- optional android.os.statsd.EventType event_id = 2;
+ optional android.stats.EventType event_id = 2;
}
/**
@@ -2154,7 +2182,7 @@ message KernelWakelock {
optional int32 version = 3;
- optional int64 time = 4;
+ optional int64 time_micros = 4;
}
/**
@@ -2218,11 +2246,11 @@ message WifiActivityInfo {
// stack reported state
// TODO: replace this with proto enum
optional int32 stack_state = 2;
- // tx time in ms
+ // tx time in millis
optional uint64 controller_tx_time_millis = 3;
- // rx time in ms
+ // rx time in millis
optional uint64 controller_rx_time_millis = 4;
- // idle time in ms
+ // idle time in millis
optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 controller_energy_used = 6;
@@ -2234,9 +2262,9 @@ message WifiActivityInfo {
message ModemActivityInfo {
// timestamp(wall clock) of record creation
optional uint64 timestamp_millis = 1;
- // sleep time in ms.
+ // sleep time in millis.
optional uint64 sleep_time_millis = 2;
- // idle time in ms
+ // idle time in millis
optional uint64 controller_idle_time_millis = 3;
/**
* Tx power index
@@ -2271,11 +2299,11 @@ message BluetoothActivityInfo {
optional uint64 timestamp_millis = 1;
// bluetooth stack state
optional int32 bluetooth_stack_state = 2;
- // tx time in ms
+ // tx time in millis
optional uint64 controller_tx_time_millis = 3;
- // rx time in ms
+ // rx time in millis
optional uint64 controller_rx_time_millis = 4;
- // idle time in ms
+ // idle time in millis
optional uint64 controller_idle_time_millis = 5;
// product of current(mA), voltage(V) and time(ms)
optional uint64 energy_used = 6;
@@ -2292,13 +2320,13 @@ message ProcessMemoryState {
optional string process_name = 2;
// oom adj score.
- optional int32 oom_score = 3;
+ optional int32 oom_adj_score = 3;
// # of page-faults
- optional int64 pgfault = 4;
+ optional int64 page_fault = 4;
// # of major page-faults
- optional int64 pgmajfault = 5;
+ optional int64 page_major_fault = 5;
// RSS
optional int64 rss_in_bytes = 6;
@@ -2380,7 +2408,7 @@ message DiskSpace {
* frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
*/
message RemainingBatteryCapacity {
- optional int32 charge_uAh = 1;
+ optional int32 charge_micro_ampere_hour = 1;
}
/**
@@ -2389,7 +2417,7 @@ message RemainingBatteryCapacity {
* frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
*/
message FullBatteryCapacity {
- optional int32 capacity_uAh = 1;
+ optional int32 capacity_micro_ampere_hour = 1;
}
/**
@@ -2399,7 +2427,7 @@ message FullBatteryCapacity {
*/
message BatteryVoltage {
// The voltage of the battery, in millivolts.
- optional int32 voltage_mV = 1;
+ optional int32 voltage_millivolt = 1;
}
/**
@@ -2417,7 +2445,7 @@ message Temperature {
optional string sensor_name = 2;
// Temperature in tenths of a degree C.
- optional int32 temperature_dC = 3;
+ optional int32 temperature_deci_celsius = 3;
}
/**
@@ -2527,8 +2555,7 @@ message LooperStats {
// recorded_message_count.
//
// If recorded_message_count is different than message_count, it means data
- // collection has been sampled. All the fields below will be sampled in this
- // case.
+ // collection has been sampled. The fields below will be sampled in this case.
optional int64 recorded_message_count = 7;
// Total latency of all processed messages.
@@ -2544,6 +2571,32 @@ message LooperStats {
// True if the screen was interactive PowerManager#isInteractive at the end of the call.
optional bool screen_interactive = 10;
+
+ // Max recorded CPU usage of all processed messages.
+ optional int64 recorded_max_cpu_micros = 11;
+
+ // Max recorded latency of all processed messages.
+ optional int64 recorded_max_latency_micros = 12;
+
+ // Total number of messages we tracked the dispatching delay for. If we
+ // collected data for all the messages, message_count will be equal to
+ // recorded_delay_message_count.
+ //
+ // If recorded_delay_message_count is different than message_count, it means data
+ // collection has been sampled or/and not all messages specified the target dispatch time.
+ // The fields below will be sampled in this case.
+ optional int64 recorded_delay_message_count = 13;
+
+ // Total dispatching delay of all processed messages.
+ // Calculated as a difference between the target dispatching time (Message.when)
+ // and the actual dispatching time.
+ // Average can be computed using recorded_total_delay_millis / recorded_delay_message_count.
+ optional int64 recorded_total_delay_millis = 14;
+
+ // Max dispatching delay of all processed messages.
+ // Calculated as a difference between the target dispatching time (Message.when)
+ // and the actual dispatching time.
+ optional int64 recorded_max_delay_millis = 15;
}
/**
@@ -2662,11 +2715,288 @@ message NumFingerprints {
optional int32 num_fingerprints = 2;
}
+message AggStats {
+ optional int64 min = 1;
+
+ optional int64 average = 2;
+
+ optional int64 max = 3;
+}
+
+message ProcessStatsStateProto {
+ optional android.service.procstats.ScreenState screen_state = 1;
+
+ optional android.service.procstats.MemoryState memory_state = 2;
+
+ // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+ // and not frameworks/base/core/java/android/app/ActivityManager.java
+ optional android.service.procstats.ProcessState process_state = 3;
+
+ // Millisecond uptime duration spent in this state
+ optional int64 duration_millis = 4;
+
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_millis = 9;
+
+ // # of samples taken
+ optional int32 sample_size = 5;
+
+ // PSS is memory reserved for this process
+ optional AggStats pss = 6;
+
+ // USS is memory shared between processes, divided evenly for accounting
+ optional AggStats uss = 7;
+
+ // RSS is memory resident for this process
+ optional AggStats rss = 8;
+}
+
+// Next Tag: 7
+message ProcessStatsProto {
+ // Name of process.
+ optional string process = 1;
+
+ // Uid of the process.
+ optional int32 uid = 2;
+
+ // Information about how often kills occurred
+ message Kill {
+ // Count of excessive CPU kills
+ optional int32 cpu = 1;
+
+ // Count of kills when cached
+ optional int32 cached = 2;
+
+ // PSS stats during cached kill
+ optional AggStats cached_pss = 3;
+ }
+ optional Kill kill = 3;
+
+ // Time and memory spent in various states.
+ repeated ProcessStatsStateProto states = 5;
+
+ // Total time process has been running... screen_state, memory_state, and process_state
+ // will not be set.
+ optional ProcessStatsStateProto total_running_state = 6;
+}
+
+message PackageServiceOperationStatsProto {
+ // Operate enum: Started, Foreground, Bound, Executing
+ optional android.service.procstats.ServiceOperationState operation = 1;
+
+ // Number of times the service was in this operation.
+ optional int32 count = 2;
+
+ // Information about a state the service can be in.
+ message StateStats {
+ // Screen state enum.
+ optional android.service.procstats.ScreenState screen_state = 1;
+ // Memory state enum.
+ optional android.service.procstats.MemoryState memory_state = 2;
+
+ // duration in milliseconds.
+ optional int64 duration_millis = 3;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_millis = 4;
+ }
+ repeated StateStats state_stats = 3;
+}
+
+message PackageServiceStatsProto {
+ // Name of service component.
+ optional string service_name = 1;
+
+ // The operation stats.
+ // The package_name, package_uid, package_version, service_name will not be set to save space.
+ repeated PackageServiceOperationStatsProto operation_stats = 2;
+}
+
+message PackageAssociationSourceProcessStatsProto {
+ // Uid of the process.
+ optional int32 process_uid = 1;
+ // Process name.
+ optional string process_name = 2;
+
+ // Total count of the times this association appeared.
+ optional int32 total_count = 3;
+
+ // Millisecond uptime total duration this association was around.
+ optional int64 total_duration_millis = 4;
+
+ // Total count of the times this association became actively impacting its target process.
+ optional int32 active_count = 5;
+
+ // Information on one source in this association.
+ message StateStats {
+ // Process state enum.
+ optional android.service.procstats.ProcessState process_state = 1;
+ // Millisecond uptime duration spent in this state
+ optional int64 duration_millis = 2;
+ // Millisecond elapsed realtime duration spent in this state
+ optional int64 realtime_duration_mmillis = 3;
+ }
+ repeated StateStats active_state_stats = 6;
+}
+
+message PackageAssociationProcessStatsProto {
+ // Name of the target component.
+ optional string component_name = 1;
+ // Information on one source in this association.
+ repeated PackageAssociationSourceProcessStatsProto sources = 2;
+}
+
+
+message ProcessStatsPackageProto {
+ // Name of package.
+ optional string package = 1;
+
+ // Uid of the package.
+ optional int32 uid = 2;
+
+ // Version of the package.
+ optional int64 version = 3;
+
+ // Stats for each process running with the package loaded in to it.
+ repeated ProcessStatsProto process_stats = 4;
+
+ // Stats for each of the package's services.
+ repeated PackageServiceStatsProto service_stats = 5;
+
+ // Stats for each association with the package.
+ repeated PackageAssociationProcessStatsProto association_stats = 6;
+}
+
+message ProcessStatsSectionProto {
+ // Elapsed realtime at start of report.
+ optional int64 start_realtime_millis = 1;
+
+ // Elapsed realtime at end of report.
+ optional int64 end_realtime_millis = 2;
+
+ // CPU uptime at start of report.
+ optional int64 start_uptime_millis = 3;
+
+ // CPU uptime at end of report.
+ optional int64 end_uptime_millis = 4;
+
+ // System runtime library. e.g. "libdvm.so", "libart.so".
+ optional string runtime = 5;
+
+ // whether kernel reports swapped pss.
+ optional bool has_swapped_pss = 6;
+
+ // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
+ enum Status {
+ STATUS_UNKNOWN = 0;
+ STATUS_COMPLETE = 1;
+ STATUS_PARTIAL = 2;
+ STATUS_SHUTDOWN = 3;
+ STATUS_SYSPROPS = 4;
+ }
+ repeated Status status = 7;
+
+ // Stats for each process.
+ repeated ProcessStatsProto process_stats = 8;
+
+ // Stats for each package.
+ repeated ProcessStatsPackageProto package_stats = 9;
+}
+
/**
* Pulled from ProcessStatsService.java
*/
message ProcStats {
- optional android.service.procstats.ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
+message PowerProfileProto {
+ optional double cpu_suspend = 1;
+
+ optional double cpu_idle = 2;
+
+ optional double cpu_active = 3;
+
+ message CpuCluster {
+ optional int32 id = 1;
+ optional double cluster_power = 2;
+ optional int32 cores = 3;
+ repeated int64 speed = 4;
+ repeated double core_power = 5;
+ }
+
+ repeated CpuCluster cpu_cluster = 40;
+
+ optional double wifi_scan = 4;
+
+ optional double wifi_on = 5;
+
+ optional double wifi_active = 6;
+
+ optional double wifi_controller_idle = 7;
+
+ optional double wifi_controller_rx = 8;
+
+ optional double wifi_controller_tx = 9;
+
+ repeated double wifi_controller_tx_levels = 10;
+
+ optional double wifi_controller_operating_voltage = 11;
+
+ optional double bluetooth_controller_idle = 12;
+
+ optional double bluetooth_controller_rx = 13;
+
+ optional double bluetooth_controller_tx = 14;
+
+ optional double bluetooth_controller_operating_voltage = 15;
+
+ optional double modem_controller_sleep = 16;
+
+ optional double modem_controller_idle = 17;
+
+ optional double modem_controller_rx = 18;
+
+ repeated double modem_controller_tx = 19;
+
+ optional double modem_controller_operating_voltage = 20;
+
+ optional double gps_on = 21;
+
+ repeated double gps_signal_quality_based = 22;
+
+ optional double gps_operating_voltage = 23;
+
+ optional double bluetooth_on = 24;
+
+ optional double bluetooth_active = 25;
+
+ optional double bluetooth_at_cmd = 26;
+
+ optional double ambient_display = 27;
+
+ optional double screen_on = 28;
+
+ optional double radio_on = 29;
+
+ optional double radio_scanning = 30;
+
+ optional double radio_active = 31;
+
+ optional double screen_full = 32;
+
+ optional double audio = 33;
+
+ optional double video = 34;
+
+ optional double flashlight = 35;
+
+ optional double memory = 36;
+
+ optional double camera = 37;
+
+ optional double wifi_batched_scan = 38;
+
+ optional double battery_capacity = 39;
}
/**
@@ -2674,5 +3004,5 @@ message ProcStats {
* Pulled from PowerProfile.java
*/
message PowerProfile {
- optional com.android.internal.os.PowerProfileProto power_profile_proto = 1;
-} \ No newline at end of file
+ optional PowerProfileProto power_profile = 1;
+}
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
index c501c9f818b9..543a748adedb 100644
--- a/cmds/statsd/src/hash.cpp
+++ b/cmds/statsd/src/hash.cpp
@@ -16,6 +16,10 @@
#include "hash.h"
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
namespace android {
namespace os {
namespace statsd {
@@ -67,8 +71,10 @@ uint32_t Hash32(const char *data, size_t n, uint32_t seed) {
switch (n) {
case 3:
h ^= ByteAs32(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs32(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs32(data[0]);
h *= m;
@@ -104,16 +110,22 @@ uint64_t Hash64(const char* data, size_t n, uint64_t seed) {
switch (n) {
case 7:
h ^= ByteAs64(data[6]) << 48;
+ FALLTHROUGH_INTENDED;
case 6:
h ^= ByteAs64(data[5]) << 40;
+ FALLTHROUGH_INTENDED;
case 5:
h ^= ByteAs64(data[4]) << 32;
+ FALLTHROUGH_INTENDED;
case 4:
h ^= ByteAs64(data[3]) << 24;
+ FALLTHROUGH_INTENDED;
case 3:
h ^= ByteAs64(data[2]) << 16;
+ FALLTHROUGH_INTENDED;
case 2:
h ^= ByteAs64(data[1]) << 8;
+ FALLTHROUGH_INTENDED;
case 1:
h ^= ByteAs64(data[0]);
h *= m;
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a5dac0836238..6b8c12a893e8 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -46,6 +46,27 @@ struct log_reader_thread_data {
sp<StatsService> service;
};
+
+sp<StatsService> gStatsService = nullptr;
+
+void sigHandler(int sig) {
+ if (gStatsService != nullptr) {
+ gStatsService->Terminate();
+ }
+}
+
+void registerSigHandler()
+{
+ struct sigaction sa;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = sigHandler;
+ sigaction(SIGHUP, &sa, nullptr);
+ sigaction(SIGINT, &sa, nullptr);
+ sigaction(SIGQUIT, &sa, nullptr);
+ sigaction(SIGTERM, &sa, nullptr);
+}
+
int main(int /*argc*/, char** /*argv*/) {
// Set up the looper
sp<Looper> looper(Looper::prepare(0 /* opts */));
@@ -60,23 +81,25 @@ int main(int /*argc*/, char** /*argv*/) {
::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
// Create the service
- sp<StatsService> service = new StatsService(looper);
- if (defaultServiceManager()->addService(String16("stats"), service) != 0) {
+ gStatsService = new StatsService(looper);
+ if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
ALOGE("Failed to add service as AIDL service");
return -1;
}
- auto ret = service->registerAsService();
+ auto ret = gStatsService->registerAsService();
if (ret != ::android::OK) {
ALOGE("Failed to add service as HIDL service");
return 1; // or handle error
}
- service->sayHiToStatsCompanion();
+ registerSigHandler();
+
+ gStatsService->sayHiToStatsCompanion();
- service->Startup();
+ gStatsService->Startup();
- sp<StatsSocketListener> socketListener = new StatsSocketListener(service);
+ sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
ALOGI("using statsd socket");
// Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ab0b23cc009d..10ed7f3ebaa1 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -271,6 +271,7 @@ message ConfigMetricsReport {
ADB_DUMP = 5;
CONFIG_RESET = 6;
STATSCOMPANION_DIED = 7;
+ TERMINATION_SIGNAL_RECEIVED = 8;
}
optional DumpReportReason dump_report_reason = 8;
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 5b6f167984dc..5729febce4e2 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -152,7 +152,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
@@ -161,7 +161,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(2).atom_size());
EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
@@ -170,7 +170,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(3).atom_size());
EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
@@ -179,7 +179,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(3).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(3).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(3).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(4).atom_size());
EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
@@ -188,7 +188,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(4).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(4).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(4).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(5).atom_size());
EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
@@ -197,7 +197,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(5).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(5).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(5).atom(0).temperature().temperature_deci_celsius(), 0);
}
TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
@@ -275,7 +275,7 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100,
@@ -284,7 +284,7 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(2, data.bucket_info(2).atom_size());
EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
@@ -295,9 +295,9 @@ TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents) {
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_TRUE(data.bucket_info(2).atom(1).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(2).atom(1).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(2).atom(1).temperature().temperature_deci_celsius(), 0);
}
@@ -378,7 +378,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(0).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(1).atom_size());
EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
@@ -387,7 +387,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(1).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(1).atom(0).temperature().temperature_deci_celsius(), 0);
EXPECT_EQ(1, data.bucket_info(2).atom_size());
EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
@@ -396,7 +396,7 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_TRUE(data.bucket_info(2).atom(0).temperature().sensor_name().empty());
- EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_dc(), 0);
+ EXPECT_GT(data.bucket_info(2).atom(0).temperature().temperature_deci_celsius(), 0);
}
diff --git a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
index 2b7da6ab6d79..4f4dd011e419 100644
--- a/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
+++ b/cmds/statsd/tools/dogfood/src/com/android/statsd/dogfood/MainActivity.java
@@ -319,7 +319,7 @@ public class MainActivity extends Activity {
int[] uids = new int[]{mUids[id]};
String[] tags = new String[]{"acquire"};
StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
+ StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
StringBuilder sb = new StringBuilder();
sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
@@ -335,7 +335,7 @@ public class MainActivity extends Activity {
int[] uids = new int[]{mUids[id]};
String[] tags = new String[]{"release"};
StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags,
- StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name,
+ StatsLog.WAKELOCK_STATE_CHANGED__TYPE__PARTIAL_WAKE_LOCK, name,
StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
StringBuilder sb = new StringBuilder();
sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0)
diff --git a/cmds/statsd/tools/statsd-testdrive/Android.bp b/cmds/statsd/tools/statsd-testdrive/Android.bp
new file mode 100644
index 000000000000..f566bc7f2a53
--- /dev/null
+++ b/cmds/statsd/tools/statsd-testdrive/Android.bp
@@ -0,0 +1,11 @@
+java_binary_host {
+ name: "statsd_testdrive",
+ manifest: "manifest.txt",
+ srcs: [
+ "src/**/*.java",
+ ],
+ static_libs: [
+ "platformprotos",
+ "guava",
+ ],
+}
diff --git a/cmds/statsd/tools/statsd-testdrive/manifest.txt b/cmds/statsd/tools/statsd-testdrive/manifest.txt
new file mode 100644
index 000000000000..0266d1143245
--- /dev/null
+++ b/cmds/statsd/tools/statsd-testdrive/manifest.txt
@@ -0,0 +1 @@
+Main-class: com.android.statsd.testdrive.TestDrive
diff --git a/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java b/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java
new file mode 100644
index 000000000000..ae3e5a1b1dfa
--- /dev/null
+++ b/cmds/statsd/tools/statsd-testdrive/src/com/android/statsd/testdrive/TestDrive.java
@@ -0,0 +1,286 @@
+/*
+ * 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.statsd.testdrive;
+
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog.ConfigMetricsReport;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+
+import com.google.common.io.Files;
+import com.google.protobuf.TextFormat;
+import com.google.protobuf.TextFormat.ParseException;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestDrive {
+
+ public static final int PULL_ATOM_START = 10000;
+ public static final long ATOM_MATCHER_ID = 1234567;
+
+ public static final String UPDATE_CONFIG_CMD = "cmd stats config update";
+ public static final String DUMP_REPORT_CMD = "cmd stats dump-report";
+ public static final String REMOVE_CONFIG_CMD = "cmd stats config remove";
+ public static final String CONFIG_UID = "2000"; // shell uid
+ public static final long CONFIG_ID = 54321;
+
+ private static boolean mIsPushedAtom = false;
+
+ private static final Logger logger = Logger.getLogger(TestDrive.class.getName());
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ logger.log(Level.SEVERE, "Usage: ./test_drive <atomId>");
+ return;
+ }
+ int atomId;
+ try {
+ atomId = Integer.valueOf(args[0]);
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, "Bad atom id provided: " + args[0]);
+ return;
+ }
+ if (Atom.getDescriptor().findFieldByNumber(atomId) == null) {
+ logger.log(Level.SEVERE, "No such atom found: " + args[0]);
+ return;
+ }
+ mIsPushedAtom = atomId < PULL_ATOM_START;
+
+ TestDrive testDrive = new TestDrive();
+ try {
+ StatsdConfig config = testDrive.createConfig(atomId);
+ if (config == null) {
+ logger.log(Level.SEVERE, "Failed to create valid config.");
+ return;
+ }
+ testDrive.pushConfig(config);
+ logger.info("Pushed the following config to statsd:");
+ logger.info(config.toString());
+ if (mIsPushedAtom) {
+ logger.info(
+ "Now please play with the device to trigger the event. All events should be dumped after 1 min ...");
+ Thread.sleep(60_000);
+ } else {
+ // wait for 2 min
+ logger.info("Now wait for 2 minutes ...");
+ Thread.sleep(120_000);
+ }
+ testDrive.dumpMetrics();
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Failed to test drive: " + e.getMessage());
+ } finally {
+ testDrive.removeConfig();
+ }
+ }
+
+ private void pushConfig(StatsdConfig config) throws IOException, InterruptedException {
+ File configFile = File.createTempFile("statsdconfig", ".config");
+ configFile.deleteOnExit();
+ Files.write(config.toByteArray(), configFile);
+ String remotePath = "/data/local/tmp/" + configFile.getName();
+ runCommand(null, "adb", "push", configFile.getAbsolutePath(), remotePath);
+ runCommand(
+ null, "adb", "shell", "cat", remotePath, "|", UPDATE_CONFIG_CMD,
+ String.valueOf(CONFIG_ID));
+ }
+
+ private void removeConfig() {
+ try {
+ runCommand(null, "adb", "shell", REMOVE_CONFIG_CMD, String.valueOf(CONFIG_ID));
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Failed to remove config: " + e.getMessage());
+ }
+ }
+
+ // Runs a shell command. Output should go to outputFile. Returns error string.
+ private String runCommand(File outputFile, String... commands)
+ throws IOException, InterruptedException {
+ // Run macro on target
+ ProcessBuilder pb = new ProcessBuilder(commands);
+ // pb.redirectErrorStream(true);
+
+ if (outputFile != null && outputFile.exists() && outputFile.canWrite()) {
+ pb.redirectOutput(outputFile);
+ }
+ Process process = pb.start();
+
+ // capture any errors
+ StringBuilder out = new StringBuilder();
+ // Read output
+ BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ String line = null, previous = null;
+ while ((line = br.readLine()) != null) {
+ if (!line.equals(previous)) {
+ previous = line;
+ out.append(line).append('\n');
+ logger.fine(line);
+ }
+ }
+
+ // Check result
+ if (process.waitFor() == 0) {
+ logger.info("Success!");
+ } else {
+ // Abnormal termination: Log command parameters and output and throw ExecutionException
+ logger.log(Level.SEVERE, out.toString());
+ }
+ return out.toString();
+ }
+
+ private StatsdConfig createConfig(int atomId) {
+ try {
+ if (mIsPushedAtom) {
+ return createSimpleEventMetricConfig(atomId);
+ } else {
+ return createSimpleGaugeMetricConfig(atomId);
+ }
+ } catch (ParseException e) {
+ logger.log(
+ Level.SEVERE,
+ "Failed to parse the config! line: "
+ + e.getLine()
+ + " col: "
+ + e.getColumn()
+ + " "
+ + e.getMessage());
+ }
+ return null;
+ }
+
+ private StatsdConfig createSimpleEventMetricConfig(int atomId) throws ParseException {
+ StatsdConfig.Builder baseBuilder = getSimpleEventMetricBaseConfig();
+ baseBuilder.addAtomMatcher(createAtomMatcher(atomId));
+ return baseBuilder.build();
+ }
+
+ private StatsdConfig createSimpleGaugeMetricConfig(int atomId) throws ParseException {
+ StatsdConfig.Builder baseBuilder = getSimpleGaugeMetricBaseConfig();
+ baseBuilder.addAtomMatcher(createAtomMatcher(atomId));
+ return baseBuilder.build();
+ }
+
+ private AtomMatcher createAtomMatcher(int atomId) {
+ AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
+ atomMatcherBuilder
+ .setId(ATOM_MATCHER_ID)
+ .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder().setAtomId(atomId));
+ return atomMatcherBuilder.build();
+ }
+
+ private StatsdConfig.Builder getSimpleEventMetricBaseConfig() throws ParseException {
+ StatsdConfig.Builder builder = StatsdConfig.newBuilder();
+ TextFormat.merge(EVENT_BASE_CONFIG_SRTR, builder);
+ return builder;
+ }
+
+ private StatsdConfig.Builder getSimpleGaugeMetricBaseConfig() throws ParseException {
+ StatsdConfig.Builder builder = StatsdConfig.newBuilder();
+ TextFormat.merge(GAUGE_BASE_CONFIG_STR, builder);
+ return builder;
+ }
+
+ private ConfigMetricsReportList getReportList() throws Exception {
+ try {
+ File outputFile = File.createTempFile("statsdret", ".bin");
+ outputFile.deleteOnExit();
+ runCommand(
+ outputFile,
+ "adb",
+ "shell",
+ DUMP_REPORT_CMD,
+ String.valueOf(CONFIG_ID),
+ "--include_current_bucket",
+ "--proto");
+ ConfigMetricsReportList reportList =
+ ConfigMetricsReportList.parseFrom(new FileInputStream(outputFile));
+ return reportList;
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ logger.log(
+ Level.SEVERE,
+ "Failed to fetch and parse the statsd output report. "
+ + "Perhaps there is not a valid statsd config for the requested "
+ + "uid="
+ + CONFIG_UID
+ + ", id="
+ + CONFIG_ID
+ + ".");
+ throw (e);
+ }
+ }
+
+ private void dumpMetrics() throws Exception {
+ ConfigMetricsReportList reportList = getReportList();
+ // We may get multiple reports. Take the last one.
+ ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
+ // Really should be only one metric.
+ if (report.getMetricsCount() != 1) {
+ logger.log(Level.SEVERE, "Only one report metric expected, got "
+ + report.getMetricsCount());
+ return;
+ }
+
+ logger.info("Got following metric data dump:");
+ logger.info(report.getMetrics(0).toString());
+ }
+
+ private static final String EVENT_BASE_CONFIG_SRTR =
+ "id: 12345\n"
+ + "event_metric {\n"
+ + " id: 1111\n"
+ + " what: 1234567\n"
+ + "}\n"
+ + "allowed_log_source: \"AID_GRAPHICS\"\n"
+ + "allowed_log_source: \"AID_INCIDENTD\"\n"
+ + "allowed_log_source: \"AID_STATSD\"\n"
+ + "allowed_log_source: \"AID_RADIO\"\n"
+ + "allowed_log_source: \"com.android.systemui\"\n"
+ + "allowed_log_source: \"com.android.vending\"\n"
+ + "allowed_log_source: \"AID_SYSTEM\"\n"
+ + "allowed_log_source: \"AID_ROOT\"\n"
+ + "allowed_log_source: \"AID_BLUETOOTH\"\n"
+ + "\n"
+ + "hash_strings_in_metric_report: false";
+
+ private static final String GAUGE_BASE_CONFIG_STR =
+ "id: 56789\n"
+ + "gauge_metric {\n"
+ + " id: 2222\n"
+ + " what: 1234567\n"
+ + " gauge_fields_filter {\n"
+ + " include_all: true\n"
+ + " }\n"
+ + " bucket: ONE_MINUTE\n"
+ + "}\n"
+ + "allowed_log_source: \"AID_GRAPHICS\"\n"
+ + "allowed_log_source: \"AID_INCIDENTD\"\n"
+ + "allowed_log_source: \"AID_STATSD\"\n"
+ + "allowed_log_source: \"AID_RADIO\"\n"
+ + "allowed_log_source: \"com.android.systemui\"\n"
+ + "allowed_log_source: \"com.android.vending\"\n"
+ + "allowed_log_source: \"AID_SYSTEM\"\n"
+ + "allowed_log_source: \"AID_ROOT\"\n"
+ + "allowed_log_source: \"AID_BLUETOOTH\"\n"
+ + "\n"
+ + "hash_strings_in_metric_report: false";
+}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 6af34f9151b9..857c39045085 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -523,7 +523,6 @@ 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;->setAirplaneMode(Z)V
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
@@ -2216,6 +2215,7 @@ Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKey(Ljava/security/PrivateKey
Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2791,15 +2791,6 @@ Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ss
Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale;
-Llibcore/io/Memory;->peekByte(J)B
-Llibcore/io/Memory;->peekByteArray(J[BII)V
-Llibcore/io/Memory;->peekInt(JZ)I
-Llibcore/io/Memory;->peekLong(JZ)J
-Llibcore/io/Memory;->pokeByte(JB)V
-Llibcore/io/Memory;->pokeByteArray(J[BII)V
-Llibcore/io/Memory;->pokeInt(JIZ)V
-Llibcore/io/Memory;->pokeLong(JJZ)V
-Llibcore/io/Streams;->copy(Ljava/io/InputStream;Ljava/io/OutputStream;)I
Llibcore/util/BasicLruCache;->map:Ljava/util/LinkedHashMap;
Llibcore/util/ZoneInfo;->mTransitions:[J
Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
diff --git a/config/hiddenapi-max-sdk-p-blacklist.txt b/config/hiddenapi-max-sdk-p-blacklist.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/config/hiddenapi-max-sdk-p-blacklist.txt
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
index f9284e67f9c3..967aa0424b1d 100644
--- a/core/java/android/accounts/AccountAuthenticatorActivity.java
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -48,7 +48,7 @@ public class AccountAuthenticatorActivity extends Activity {
}
/**
- * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
+ * Retrieves the AccountAuthenticatorResponse from either the intent of the icicle, if the
* icicle is non-zero.
* @param icicle the save instance data of this Activity, may be null
*/
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index 5483c49aef54..bcb94d11ea3c 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -76,7 +76,7 @@ public abstract class Keyframe implements Cloneable {
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
* of time elapsed of the overall animation duration.
* @param value The value that the object will animate to as the animation time approaches
- * the time in this keyframe, and the the value animated from as the time passes the time in
+ * the time in this keyframe, and the value animated from as the time passes the time in
* this keyframe.
*/
public static Keyframe ofInt(float fraction, int value) {
@@ -108,7 +108,7 @@ public abstract class Keyframe implements Cloneable {
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
* of time elapsed of the overall animation duration.
* @param value The value that the object will animate to as the animation time approaches
- * the time in this keyframe, and the the value animated from as the time passes the time in
+ * the time in this keyframe, and the value animated from as the time passes the time in
* this keyframe.
*/
public static Keyframe ofFloat(float fraction, float value) {
@@ -140,7 +140,7 @@ public abstract class Keyframe implements Cloneable {
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
* of time elapsed of the overall animation duration.
* @param value The value that the object will animate to as the animation time approaches
- * the time in this keyframe, and the the value animated from as the time passes the time in
+ * the time in this keyframe, and the value animated from as the time passes the time in
* this keyframe.
*/
public static Keyframe ofObject(float fraction, Object value) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 482ef2d1a6fd..aca80b494b78 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2952,7 +2952,7 @@ public class Activity extends ContextThemeWrapper
/**
* Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes
* will start an application-defined search. (If the application or activity does not
- * actually define a search, the the keys will be ignored.)
+ * actually define a search, the keys will be ignored.)
*
* <p>See {@link android.app.SearchManager android.app.SearchManager} for more details.
*
@@ -3252,7 +3252,7 @@ public class Activity extends ContextThemeWrapper
* interacted with the device in some way while your activity is running.
* This callback and {@link #onUserLeaveHint} are intended to help
* activities manage status bar notifications intelligently; specifically,
- * for helping activities determine the proper time to cancel a notfication.
+ * for helping activities determine the proper time to cancel a notification.
*
* <p>All calls to your activity's {@link #onUserLeaveHint} callback will
* be accompanied by calls to {@link #onUserInteraction}. This
@@ -7906,7 +7906,7 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Specifies whether an {@link Activity} should be shown on top of the the lock screen whenever
+ * Specifies whether an {@link Activity} should be shown on top of the lock screen whenever
* the lockscreen is up and the activity is resumed. Normally an activity will be transitioned
* to the stopped state if it is started while the lockscreen is up, but with this flag set the
* activity will remain in the resumed state visible on-top of the lock screen. This value can
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 784ce04908fe..296c063f5379 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.UserInfo;
import android.os.Bundle;
@@ -242,4 +243,10 @@ public abstract class ActivityManagerInternal {
throws TransactionTooLargeException;
public abstract void disconnectActivityFromServices(Object connectionHolder);
+ public abstract void cleanUpServices(int userId, ComponentName component, Intent baseIntent);
+ public abstract ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId);
+ public abstract void ensureBootCompleted();
+ public abstract void updateOomLevelsForDisplay(int displayId);
+ public abstract boolean isActivityStartsLoggingEnabled();
+ public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 63c61d319a44..3c9a2d4ab7e3 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1501,7 +1501,7 @@ public class ActivityOptions {
}
/**
- * Ask the the system track that time the user spends in the app being launched, and
+ * Ask the system track that time the user spends in the app being launched, and
* report it back once done. The report will be sent to the given receiver, with
* the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
* filled in.
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index af8aa4e7c3b4..b8fe2f13d328 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -45,6 +45,12 @@ public class ActivityTaskManager {
public static final int INVALID_STACK_ID = -1;
/**
+ * Invalid task ID.
+ * @hide
+ */
+ public static final int INVALID_TASK_ID = -1;
+
+ /**
* Parameter to {@link IActivityTaskManager#setTaskWindowingModeSplitScreenPrimary} which
* specifies the position of the created docked stack at the top half of the screen if
* in portrait mode or at the left half of the screen if in landscape mode.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6754df9ac6fd..9d3c5c6417af 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5054,7 +5054,7 @@ public final class ActivityThread extends ClientTransactionHandler {
private void performConfigurationChangedForActivity(ActivityClientRecord r,
Configuration newBaseConfig) {
performConfigurationChangedForActivity(r, newBaseConfig,
- r.activity.getDisplay().getDisplayId(), false /* movedToDifferentDisplay */);
+ r.activity.getDisplayId(), false /* movedToDifferentDisplay */);
}
/**
@@ -5406,7 +5406,7 @@ public final class ActivityThread extends ClientTransactionHandler {
return;
}
final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
- && displayId != r.activity.getDisplay().getDisplayId();
+ && displayId != r.activity.getDisplayId();
// Perform updates.
r.overrideConfig = overrideConfig;
@@ -5666,7 +5666,7 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
- GraphicsEnvironment.getInstance().setup(context);
+ GraphicsEnvironment.getInstance().setup(context, mCoreSettings);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/core/java/android/app/AppDetailsActivity.java b/core/java/android/app/AppDetailsActivity.java
new file mode 100644
index 000000000000..cd36e634f54b
--- /dev/null
+++ b/core/java/android/app/AppDetailsActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Helper activity that forwards you to app details page.
+ *
+ * @hide
+ */
+public class AppDetailsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(android.net.Uri.fromParts("package", getPackageName(), null));
+ startActivity(intent);
+ finish();
+ }
+}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a05d01b5ad9a..a30ae799bd3d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -431,9 +431,11 @@ public class AppOpsManager {
public static final int OP_BLUETOOTH_SCAN = 77;
/** @hide Use the BiometricPrompt/BiometricManager APIs. */
public static final int OP_USE_BIOMETRIC = 78;
+ /** @hide Physical activity recognition. */
+ public static final int OP_ACTIVITY_RECOGNITION = 79;
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 79;
+ public static final int _NUM_OP = 80;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -681,6 +683,9 @@ public class AppOpsManager {
/** @hide Use the BiometricPrompt/BiometricManager APIs. */
public static final String OPSTR_USE_BIOMETRIC = "android:use_biometric";
+ /** @hide Recognize physical activity. */
+ public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
+
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
@@ -722,6 +727,8 @@ public class AppOpsManager {
OP_CAMERA,
// Body sensors
OP_BODY_SENSORS,
+ // Activity recognition
+ OP_ACTIVITY_RECOGNITION,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
@@ -819,6 +826,7 @@ public class AppOpsManager {
OP_START_FOREGROUND, // START_FOREGROUND
OP_COARSE_LOCATION, // BLUETOOTH_SCAN
OP_USE_BIOMETRIC, // BIOMETRIC
+ OP_ACTIVITY_RECOGNITION, // ACTIVITY_RECOGNITION
};
/**
@@ -904,6 +912,7 @@ public class AppOpsManager {
OPSTR_START_FOREGROUND,
OPSTR_BLUETOOTH_SCAN,
OPSTR_USE_BIOMETRIC,
+ OPSTR_ACTIVITY_RECOGNITION,
};
/**
@@ -990,6 +999,7 @@ public class AppOpsManager {
"START_FOREGROUND",
"BLUETOOTH_SCAN",
"USE_BIOMETRIC",
+ "ACTIVITY_RECOGNITION",
};
/**
@@ -1077,6 +1087,7 @@ public class AppOpsManager {
Manifest.permission.FOREGROUND_SERVICE,
null, // no permission for OP_BLUETOOTH_SCAN
Manifest.permission.USE_BIOMETRIC,
+ Manifest.permission.ACTIVITY_RECOGNITION,
};
/**
@@ -1164,6 +1175,7 @@ public class AppOpsManager {
null, // START_FOREGROUND
null, // maybe should be UserManager.DISALLOW_SHARE_LOCATION, //BLUETOOTH_SCAN
null, // USE_BIOMETRIC
+ null, // ACTIVITY_RECOGNITION
};
/**
@@ -1250,6 +1262,7 @@ public class AppOpsManager {
false, // START_FOREGROUND
true, // BLUETOOTH_SCAN
false, // USE_BIOMETRIC
+ false, // ACTIVITY_RECOGNITION
};
/**
@@ -1335,6 +1348,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // START_FOREGROUND
AppOpsManager.MODE_ALLOWED, // BLUETOOTH_SCAN
AppOpsManager.MODE_ALLOWED, // USE_BIOMETRIC
+ AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION
};
/**
@@ -1424,6 +1438,7 @@ public class AppOpsManager {
false, // START_FOREGROUND
false, // BLUETOOTH_SCAN
false, // USE_BIOMETRIC
+ false, // ACTIVITY_RECOGNITION
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 264029b6ace7..fcd9a0511265 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -55,6 +55,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
@@ -85,6 +86,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IconDrawableFactory;
import android.util.LauncherIcons;
@@ -2255,9 +2257,19 @@ public class ApplicationPackageManager extends PackageManager {
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
String dialogMessage) {
+ final SuspendDialogInfo dialogInfo = !TextUtils.isEmpty(dialogMessage)
+ ? new SuspendDialogInfo.Builder().setMessage(dialogMessage).build()
+ : null;
+ return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras, dialogInfo);
+ }
+
+ @Override
+ public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+ PersistableBundle appExtras, PersistableBundle launcherExtras,
+ SuspendDialogInfo dialogInfo) {
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
- launcherExtras, dialogMessage, mContext.getOpPackageName(),
+ launcherExtras, dialogInfo, mContext.getOpPackageName(),
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 77f639535b15..dc707e892d9a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2088,8 +2088,7 @@ class ContextImpl extends Context {
ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken,
new UserHandle(UserHandle.getUserId(application.uid)), flags, null);
- final int displayId = mDisplay != null
- ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ final int displayId = getDisplayId();
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo()));
@@ -2124,8 +2123,7 @@ class ContextImpl extends Context {
ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user,
flags, null);
- final int displayId = mDisplay != null
- ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ final int displayId = getDisplayId();
c.setResources(createResources(mActivityToken, pi, null, displayId, null,
getDisplayAdjustments(displayId).getCompatibilityInfo()));
@@ -2152,8 +2150,7 @@ class ContextImpl extends Context {
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName,
mActivityToken, mUser, mFlags, classLoader);
- final int displayId = mDisplay != null
- ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ final int displayId = getDisplayId();
context.setResources(ResourcesManager.getInstance().getResources(
mActivityToken,
@@ -2177,7 +2174,7 @@ class ContextImpl extends Context {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName,
mActivityToken, mUser, mFlags, mClassLoader);
- final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ final int displayId = getDisplayId();
context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo()));
return context;
@@ -2250,6 +2247,11 @@ class ContextImpl extends Context {
}
@Override
+ public int getDisplayId() {
+ return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+ }
+
+ @Override
public void updateDisplay(int displayId) {
mDisplay = mResourcesManager.getAdjustedDisplay(displayId, mResources);
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 49917b40521d..dbc4e34decf4 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2259,7 +2259,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Sets whether the the exit transition and enter transition overlap or not.
+ * Sets whether the exit transition and enter transition overlap or not.
* When true, the enter transition will start as soon as possible. When false, the
* enter transition will wait until the exit transition completes before starting.
*
@@ -2272,7 +2272,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Returns whether the the exit transition and enter transition overlap or not.
+ * Returns whether the exit transition and enter transition overlap or not.
* When true, the enter transition will start as soon as possible. When false, the
* enter transition will wait until the exit transition completes before starting.
*
@@ -2286,7 +2286,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Sets whether the the return transition and reenter transition overlap or not.
+ * Sets whether the return transition and reenter transition overlap or not.
* When true, the reenter transition will start as soon as possible. When false, the
* reenter transition will wait until the return transition completes before starting.
*
@@ -2299,7 +2299,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
- * Returns whether the the return transition and reenter transition overlap or not.
+ * Returns whether the return transition and reenter transition overlap or not.
* When true, the reenter transition will start as soon as possible. When false, the
* reenter transition will wait until the return transition completes before starting.
*
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index b720df8afc8f..853fccf3df7c 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -561,7 +561,7 @@ public class KeyguardManager {
* This will, if the keyguard is secure, bring up the unlock screen of
* the keyguard.
*
- * @param callback Let's you know whether the operation was succesful and
+ * @param callback Lets you know whether the operation was successful and
* it is safe to launch anything that would normally be considered safe
* once the user has gotten past the keyguard.
*/
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 81df447816d1..4f41da6e52fb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -37,6 +38,7 @@ import android.content.pm.ShortcutInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -68,6 +70,7 @@ import android.text.style.RelativeSizeSpan;
import android.text.style.TextAppearanceSpan;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
@@ -3129,6 +3132,37 @@ public class Notification implements Parcelable
return false;
}
+
+ /**
+ * Finds and returns a remote input and its corresponding action.
+ *
+ * @param requiresFreeform requires the remoteinput to allow freeform or not.
+ * @return the result pair, {@code null} if no result is found.
+ *
+ * @hide
+ */
+ @Nullable
+ public Pair<RemoteInput, Action> findRemoteInputActionPair(boolean requiresFreeform) {
+ if (actions == null) {
+ return null;
+ }
+ for (Notification.Action action : actions) {
+ if (action.getRemoteInputs() == null) {
+ continue;
+ }
+ RemoteInput resultRemoteInput = null;
+ for (RemoteInput remoteInput : action.getRemoteInputs()) {
+ if (remoteInput.getAllowFreeFormInput() || !requiresFreeform) {
+ resultRemoteInput = remoteInput;
+ }
+ }
+ if (resultRemoteInput != null) {
+ return Pair.create(resultRemoteInput, action);
+ }
+ }
+ return null;
+ }
+
/**
* Builder class for {@link Notification} objects.
*
@@ -6203,7 +6237,7 @@ public class Notification implements Parcelable
public abstract boolean areNotificationsVisiblyDifferent(Style other);
/**
- * @return the the text that should be displayed in the statusBar when heads-upped.
+ * @return the text that should be displayed in the statusBar when heads-upped.
* If {@code null} is returned, the default implementation will be used.
*
* @hide
@@ -6690,7 +6724,7 @@ public class Notification implements Parcelable
}
/**
- * @return the the text that should be displayed in the statusBar when heads upped.
+ * @return the text that should be displayed in the statusBar when heads upped.
* If {@code null} is returned, the default implementation will be used.
*
* @hide
@@ -7346,7 +7380,7 @@ public class Notification implements Parcelable
}
/**
- * Get the the Uri pointing to the content of the message. Can be null, in which case
+ * Get the Uri pointing to the content of the message. Can be null, in which case
* {@see #getText()} is used.
*/
public Uri getDataUri() {
@@ -7727,8 +7761,17 @@ public class Notification implements Parcelable
* @see Notification.Builder#setColorized(boolean)
*/
public static class MediaStyle extends Style {
+ // Changing max media buttons requires also changing templates
+ // (notification_template_material_media and notification_template_material_big_media).
static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
static final int MAX_MEDIA_BUTTONS = 5;
+ @IdRes private static final int[] MEDIA_BUTTON_IDS = {
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
+ };
private int[] mActionsToShowInCompact = null;
private MediaSession.Token mToken;
@@ -7842,15 +7885,16 @@ public class Notification implements Parcelable
return false;
}
- private RemoteViews generateMediaActionButton(Action action, int color) {
+ private void bindMediaActionButton(RemoteViews container, @IdRes int buttonId,
+ Action action, int color) {
final boolean tombstone = (action.actionIntent == null);
- RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
- R.layout.notification_material_media_action);
- button.setImageViewIcon(R.id.action0, action.getIcon());
+ container.setViewVisibility(buttonId, View.VISIBLE);
+ container.setImageViewIcon(buttonId, action.getIcon());
// If the action buttons should not be tinted, then just use the default
// notification color. Otherwise, just use the passed-in color.
- Configuration currentConfig = mBuilder.mContext.getResources().getConfiguration();
+ Resources resources = mBuilder.mContext.getResources();
+ Configuration currentConfig = resources.getConfiguration();
boolean inNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized()
@@ -7858,13 +7902,21 @@ public class Notification implements Parcelable
: ContrastColorUtil.resolveColor(mBuilder.mContext,
Notification.COLOR_DEFAULT, inNightMode);
- button.setDrawableTint(R.id.action0, false, tintColor,
+ container.setDrawableTint(buttonId, false, tintColor,
PorterDuff.Mode.SRC_ATOP);
+
+ final TypedArray typedArray = mBuilder.mContext.obtainStyledAttributes(
+ new int[]{ android.R.attr.colorControlHighlight });
+ int rippleAlpha = Color.alpha(typedArray.getColor(0, 0));
+ typedArray.recycle();
+ int rippleColor = Color.argb(rippleAlpha, Color.red(tintColor), Color.green(tintColor),
+ Color.blue(tintColor));
+ container.setRippleDrawableColor(buttonId, ColorStateList.valueOf(rippleColor));
+
if (!tombstone) {
- button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
+ container.setOnClickPendingIntent(buttonId, action.actionIntent);
}
- button.setContentDescription(R.id.action0, action.title);
- return button;
+ container.setContentDescription(buttonId, action.title);
}
private RemoteViews makeMediaContentView() {
@@ -7873,21 +7925,20 @@ public class Notification implements Parcelable
null /* result */);
final int numActions = mBuilder.mActions.size();
- final int N = mActionsToShowInCompact == null
+ final int numActionsToShow = mActionsToShowInCompact == null
? 0
: Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
- view.removeAllViews(com.android.internal.R.id.media_actions);
- if (N > 0) {
- for (int i = 0; i < N; i++) {
- if (i >= numActions) {
- throw new IllegalArgumentException(String.format(
- "setShowActionsInCompactView: action %d out of bounds (max %d)",
- i, numActions - 1));
- }
-
+ if (numActionsToShow > numActions) {
+ throw new IllegalArgumentException(String.format(
+ "setShowActionsInCompactView: action %d out of bounds (max %d)",
+ numActions, numActions - 1));
+ }
+ for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) {
+ if (i < numActionsToShow) {
final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
- final RemoteViews button = generateMediaActionButton(action, getActionColor());
- view.addView(com.android.internal.R.id.media_actions, button);
+ bindMediaActionButton(view, MEDIA_BUTTON_IDS[i], action, getActionColor());
+ } else {
+ view.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
}
}
handleImage(view);
@@ -7917,12 +7968,12 @@ public class Notification implements Parcelable
RemoteViews big = mBuilder.applyStandardTemplate(
R.layout.notification_template_material_big_media, false, null /* result */);
- if (actionCount > 0) {
- big.removeAllViews(com.android.internal.R.id.media_actions);
- for (int i = 0; i < actionCount; i++) {
- final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
+ for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) {
+ if (i < actionCount) {
+ bindMediaActionButton(big, MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i),
getActionColor());
- big.addView(com.android.internal.R.id.media_actions, button);
+ } else {
+ big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE);
}
}
handleImage(big);
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 9539f3464eca..acca6fc177b8 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -169,7 +169,7 @@ public class SearchManager
* Intent extra data key: Use this key with Intent.ACTION_SEARCH and
* {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
* to obtain the action message that was defined for a particular search action key and/or
- * suggestion. It will be null if the search was launched by typing "enter", touched the the
+ * suggestion. It will be null if the search was launched by typing "enter", touching the
* "GO" button, or other means not involving any action key.
*/
public final static String ACTION_MSG = "action_msg";
@@ -404,7 +404,7 @@ public class SearchManager
* Column name for suggestions cursor. <i>Optional.</i> If your content is rentable, you
* should provide this column to specify the displayable string representation of the rental
* price of your content including the currency and the amount. If it's free, you should
- * provide localized string to specify that it's free. This column can be ommitted if the
+ * provide localized string to specify that it's free. This column can be omitted if the
* content is not applicable to rent.
*/
public final static String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
@@ -579,7 +579,7 @@ public class SearchManager
*
* @param initialQuery A search string can be pre-entered here, but this
* is typically null or empty.
- * @param selectInitialQuery If true, the intial query will be preselected, which means that
+ * @param selectInitialQuery If true, the initial query will be preselected, which means that
* any further typing will replace it. This is useful for cases where an entire pre-formed
* query is being inserted. If false, the selection point will be placed at the end of the
* inserted query. This is useful when the inserted query is text that the user entered,
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6c87fe75740e..77cebc8f408d 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -385,7 +385,7 @@ final class SystemServiceRegistry {
new ServiceFetcher<InputMethodManager>() {
@Override
public InputMethodManager getService(ContextImpl ctx) {
- return InputMethodManager.forContext(ctx);
+ return InputMethodManager.forContext(ctx.getOuterContext());
}});
registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 09ab67186266..74fb4df112b8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3399,7 +3399,7 @@ public class DevicePolicyManager {
* restrictions on the parent profile.
*
* @param admin The name of the admin component to check, or {@code null} to aggregate
- * accross all participating admins.
+ * across all participating admins.
* @return The timeout in milliseconds or 0 if not configured for the provided admin.
*/
public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
@@ -5224,13 +5224,30 @@ public class DevicePolicyManager {
}
/**
- * @return ID of the user who runs device owner, or {@link UserHandle#USER_NULL} if there's
- * no device owner.
+ * @return Handle of the user who runs device owner, or {@code null} if there's no device owner.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
@SystemApi
+ public @Nullable UserHandle getDeviceOwnerUser() {
+ if (mService != null) {
+ try {
+ int userId = mService.getDeviceOwnerUserId();
+
+ if (userId != UserHandle.USER_NULL) {
+ return UserHandle.of(userId);
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ */
public int getDeviceOwnerUserId() {
if (mService != null) {
try {
@@ -5653,6 +5670,20 @@ public class DevicePolicyManager {
@RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
conditional = true)
@SystemApi
+ public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) {
+ if (mService != null) {
+ try {
+ return mService.getProfileOwnerAsUser(user.getIdentifier());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @hide
+ */
public @Nullable ComponentName getProfileOwnerAsUser(final int userId) {
if (mService != null) {
try {
@@ -5703,6 +5734,37 @@ public class DevicePolicyManager {
}
/**
+ * Returns whether the specified package can read the device identifiers.
+ *
+ * @param packageName The package name of the app to check for device identifier access.
+ * @return whether the package can read the device identifiers.
+ *
+ * @hide
+ */
+ public boolean checkDeviceIdentifierAccess(String packageName) {
+ return checkDeviceIdentifierAccessAsUser(packageName, myUserId());
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_USERS, conditional = true)
+ public boolean checkDeviceIdentifierAccessAsUser(String packageName, int userId) {
+ throwIfParentInstance("checkDeviceIdentifierAccessAsUser");
+ if (packageName == null) {
+ return false;
+ }
+ if (mService != null) {
+ try {
+ return mService.checkDeviceIdentifierAccess(packageName, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Called by a profile owner or device owner to set a default activity that the system selects
* to handle intents that match the given {@link IntentFilter}. This activity will remain the
* default intent handler even if the set of potential event handlers for the intent filter
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 35ea250828aa..5e454506e9eb 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -153,6 +153,8 @@ interface IDevicePolicyManager {
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean checkDeviceIdentifierAccess(in String packageName, int userHandle);
+
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 173b7667897e..fefb8d3fc139 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -74,6 +74,7 @@ public class AssistStructure implements Parcelable {
ComponentName mActivityComponent;
private boolean mIsHomeActivity;
private int mFlags;
+ private int mAutofillFlags;
final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
@@ -197,6 +198,7 @@ public class AssistStructure implements Parcelable {
mWriteStructure = as.waitForReady();
ComponentName.writeToParcel(as.mActivityComponent, out);
out.writeInt(as.mFlags);
+ out.writeInt(as.mAutofillFlags);
out.writeLong(as.mAcquisitionStartTime);
out.writeLong(as.mAcquisitionEndTime);
mNumWindows = as.mWindowNodes.size();
@@ -352,6 +354,7 @@ public class AssistStructure implements Parcelable {
fetchData();
mActivityComponent = ComponentName.readFromParcel(mCurParcel);
mFlags = mCurParcel.readInt();
+ mAutofillFlags = mCurParcel.readInt();
mAcquisitionStartTime = mCurParcel.readLong();
mAcquisitionEndTime = mCurParcel.readLong();
final int N = mCurParcel.readInt();
@@ -625,8 +628,6 @@ public class AssistStructure implements Parcelable {
String mIdType;
String mIdEntry;
- // TODO(b/37567426): once we have more flags, it might be better to store the individual
- // fields (viewId and childId) of the field.
AutofillId mAutofillId;
@View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
@Nullable String[] mAutofillHints;
@@ -669,11 +670,6 @@ public class AssistStructure implements Parcelable {
static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
static final int FLAGS_OPAQUE = 0x00008000;
- // TODO(b/37567426): autofill data is made of many fields and ideally we should verify
- // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
- // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
- // So, to keep thinkg simpler for now, let's just use on flag for all of them...
- static final int FLAGS_HAS_AUTOFILL_DATA = 0x80000000;
static final int FLAGS_HAS_MATRIX = 0x40000000;
static final int FLAGS_HAS_ALPHA = 0x20000000;
static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -690,7 +686,20 @@ public class AssistStructure implements Parcelable {
static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
static final int FLAGS_ALL_CONTROL = 0xfff00000;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID = 0x001;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x002;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE = 0x004;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE = 0x008;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS = 0x010;
+ static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS = 0x020;
+ static final int AUTOFILL_FLAGS_HAS_HTML_INFO = 0x040;
+ static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY = 0x080;
+ static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS = 0x100;
+ static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS = 0x200;
+ static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH = 0x400;
+
int mFlags;
+ int mAutofillFlags;
String mClassName;
CharSequence mContentDescription;
@@ -714,6 +723,8 @@ public class AssistStructure implements Parcelable {
mClassName = preader.readString();
mFlags = in.readInt();
final int flags = mFlags;
+ mAutofillFlags = in.readInt();
+ final int autofillFlags = mAutofillFlags;
if ((flags&FLAGS_HAS_ID) != 0) {
mId = in.readInt();
if (mId != View.NO_ID) {
@@ -725,22 +736,45 @@ public class AssistStructure implements Parcelable {
}
}
- if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
+ if (autofillFlags != 0) {
mSanitized = in.readInt() == 1;
- mAutofillId = in.readParcelable(null);
- mAutofillType = in.readInt();
- mAutofillHints = in.readStringArray();
- mAutofillValue = in.readParcelable(null);
- mAutofillOptions = in.readCharSequenceArray();
- final Parcelable p = in.readParcelable(null);
- if (p instanceof HtmlInfo) {
- mHtmlInfo = (HtmlInfo) p;
- }
- mMinEms = in.readInt();
- mMaxEms = in.readInt();
- mMaxLength = in.readInt();
- mTextIdEntry = preader.readString();
mImportantForAutofill = in.readInt();
+
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID) != 0) {
+ int autofillViewId = in.readInt();
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID) != 0) {
+ mAutofillId = new AutofillId(autofillViewId, in.readInt());
+ } else {
+ mAutofillId = new AutofillId(autofillViewId);
+ }
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+ mAutofillType = in.readInt();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+ mAutofillHints = in.readStringArray();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+ mAutofillValue = in.readParcelable(null);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+ mAutofillOptions = in.readCharSequenceArray();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_HTML_INFO) != 0) {
+ mHtmlInfo = in.readParcelable(null);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+ mMinEms = in.readInt();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+ mMaxEms = in.readInt();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+ mMaxLength = in.readInt();
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+ mTextIdEntry = preader.readString();
+ }
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
mX = in.readInt();
@@ -808,13 +842,11 @@ public class AssistStructure implements Parcelable {
boolean writeSensitive = true;
int flags = mFlags & ~FLAGS_ALL_CONTROL;
+ int autofillFlags = 0;
if (mId != View.NO_ID) {
flags |= FLAGS_HAS_ID;
}
- if (mAutofillId != null) {
- flags |= FLAGS_HAS_AUTOFILL_DATA;
- }
if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
|| (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
flags |= FLAGS_HAS_LARGE_COORDS;
@@ -855,11 +887,44 @@ public class AssistStructure implements Parcelable {
if (mChildren != null) {
flags |= FLAGS_HAS_CHILDREN;
}
+ if (mAutofillId != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID;
+ if (mAutofillId.isVirtual()) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID;
+ }
+ }
+ if (mAutofillValue != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE;
+ }
+ if (mAutofillType != View.AUTOFILL_TYPE_NONE) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE;
+ }
+ if (mAutofillHints != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS;
+ }
+ if (mAutofillOptions != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS;
+ }
+ if (mHtmlInfo instanceof Parcelable) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_HTML_INFO;
+ }
+ if (mMinEms > -1) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS;
+ }
+ if (mMaxEms > -1) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS;
+ }
+ if (mMaxLength > -1) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH;
+ }
+ if (mTextIdEntry != null) {
+ autofillFlags |= AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY;
+ }
pwriter.writeString(mClassName);
int writtenFlags = flags;
- if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
+ if (autofillFlags != 0 && (mSanitized || !sanitizeOnWrite)) {
// Remove 'checked' from sanitized autofill request.
writtenFlags = flags & ~FLAGS_CHECKED;
}
@@ -872,6 +937,7 @@ public class AssistStructure implements Parcelable {
}
out.writeInt(writtenFlags);
+ out.writeInt(autofillFlags);
if ((flags&FLAGS_HAS_ID) != 0) {
out.writeInt(mId);
if (mId != View.NO_ID) {
@@ -883,32 +949,51 @@ public class AssistStructure implements Parcelable {
}
}
- if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
- writeSensitive = mSanitized || !sanitizeOnWrite;
+ if (autofillFlags != 0) {
out.writeInt(mSanitized ? 1 : 0);
- out.writeParcelable(mAutofillId, 0);
- out.writeInt(mAutofillType);
- out.writeStringArray(mAutofillHints);
- final AutofillValue sanitizedValue;
- if (writeSensitive) {
- sanitizedValue = mAutofillValue;
- } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
- sanitizedValue = mAutofillOverlay.value;
- } else {
- sanitizedValue = null;
+ out.writeInt(mImportantForAutofill);
+ writeSensitive = mSanitized || !sanitizeOnWrite;
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID) != 0) {
+ out.writeInt(mAutofillId.getViewId());
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID) != 0) {
+ out.writeInt(mAutofillId.getVirtualChildId());
+ }
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+ out.writeInt(mAutofillType);
}
- out.writeParcelable(sanitizedValue, 0);
- out.writeCharSequenceArray(mAutofillOptions);
- if (mHtmlInfo instanceof Parcelable) {
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+ out.writeStringArray(mAutofillHints);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+ final AutofillValue sanitizedValue;
+ if (writeSensitive) {
+ sanitizedValue = mAutofillValue;
+ } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+ sanitizedValue = mAutofillOverlay.value;
+ } else {
+ sanitizedValue = null;
+ }
+ out.writeParcelable(sanitizedValue, 0);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+ out.writeCharSequenceArray(mAutofillOptions);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_HTML_INFO) != 0) {
out.writeParcelable((Parcelable) mHtmlInfo, 0);
- } else {
- out.writeParcelable(null, 0);
}
- out.writeInt(mMinEms);
- out.writeInt(mMaxEms);
- out.writeInt(mMaxLength);
- pwriter.writeString(mTextIdEntry);
- out.writeInt(mImportantForAutofill);
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+ out.writeInt(mMinEms);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+ out.writeInt(mMaxEms);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+ out.writeInt(mMaxLength);
+ }
+ if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+ pwriter.writeString(mTextIdEntry);
+ }
}
if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
out.writeInt(mX);
@@ -1002,7 +1087,7 @@ public class AssistStructure implements Parcelable {
}
/**
- * Gets the the type of value that can be used to autofill the view contents.
+ * Gets the type of value that can be used to autofill the view contents.
*
* <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
*
@@ -1028,7 +1113,7 @@ public class AssistStructure implements Parcelable {
}
/**
- * Gets the the value of this view.
+ * Gets the value of this view.
*
* <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
* not for assist purposes.
@@ -1350,7 +1435,7 @@ public class AssistStructure implements Parcelable {
}
/**
- * Returns the the list of locales associated with this view.
+ * Returns the list of locales associated with this view.
*/
@Nullable public LocaleList getLocaleList() {
return mLocaleList;
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index df27d583d361..c983d4f68710 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,6 +29,7 @@ import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -222,6 +223,18 @@ public abstract class BackupAgent extends ContextWrapper {
}
/**
+ * Provided as a convenience for agent implementations that need an opportunity
+ * to do one-time initialization before the actual backup or restore operation
+ * is begun with information about the calling user.
+ * <p>
+ *
+ * @hide
+ */
+ public void onCreate(UserHandle user) {
+ onCreate();
+ }
+
+ /**
* Provided as a convenience for agent implementations that need to do some
* sort of shutdown process after backup or restore is completed.
* <p>
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 30d5fbc7fe99..0aa053580a6d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -107,20 +107,6 @@ public final class BluetoothDevice implements Parcelable {
"android.bluetooth.device.action.FOUND";
/**
- * Broadcast Action: Remote device disappeared.
- * <p>Sent when a remote device that was found in the last discovery is not
- * found in the current discovery.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String ACTION_DISAPPEARED =
- "android.bluetooth.device.action.DISAPPEARED";
-
- /**
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
@@ -654,7 +640,7 @@ public final class BluetoothDevice implements Parcelable {
public static final int ACCESS_REJECTED = 2;
/**
- * No preferrence of physical transport for GATT connections to remote dual-mode devices
+ * No preference of physical transport for GATT connections to remote dual-mode devices
*/
public static final int TRANSPORT_AUTO = 0;
@@ -1971,9 +1957,7 @@ public final class BluetoothDevice implements Parcelable {
* <p>The remote device will be authenticated and communication on this socket will be
* encrypted.
* <p> Use this socket if an authenticated socket link is possible. Authentication refers
- * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
- * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
- * int)}.
+ * to the authentication of the link key to prevent man-in-the-middle type of attacks.
*
* @param psm dynamic PSM value from remote device
* @return a CoC #BluetoothSocket ready for an outgoing connection
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 29d5a1c583a1..9b7c173a1ec5 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -1292,7 +1292,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>After all characteristics have been queued up and verified,
* {@link #executeReliableWrite} will execute all writes. If a characteristic
* was not written correctly, calling {@link #abortReliableWrite} will
- * cancel the current transaction without commiting any values on the
+ * cancel the current transaction without committing any values on the
* remote device.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index ef1b0bd71885..13b1b4f93cf0 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -522,7 +522,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
* invoked when the connection state changes as a result of this function.
*
- * <p>The autoConnect paramter determines whether to actively connect to
+ * <p>The autoConnect parameter determines whether to actively connect to
* the remote device, or rather passively scan and finalize the connection
* when the remote device is in range/available. Generally, the first ever
* connection to a device should be direct (autoConnect set to false) and
@@ -695,7 +695,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Add a service to the list of services to be hosted.
*
- * <p>Once a service has been addded to the the list, the service and its
+ * <p>Once a service has been addded to the list, the service and its
* included characteristics will be provided by the local device.
*
* <p>If the local device has already exposed services when this function
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 758c68db1c5f..4e886250b4fa 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,8 +203,8 @@ public final class BluetoothServerSocket implements Closeable {
/**
* Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
* Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
- * {@link BluetoothAdapter.listenUsingL2capChannel()} or {@link
- * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
+ * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
+ * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
* method is called on non-L2CAP server sockets.
*
* @return the assigned PSM or LE_PSM value depending on transport
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index 58a3696fc092..51324fdb01ff 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -56,7 +56,7 @@ public abstract class AdvertisingSetCallback {
/**
* Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
* indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet
- * contains the started set and it is advertising. If error occured, advertisingSet is
+ * contains the started set and it is advertising. If error occurred, advertisingSet is
* null, and status will be set to proper error code.
*
* @param advertisingSet The advertising set that was started or null if error.
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index b528e397906f..a086a308d0d9 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -95,7 +95,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* the SyncManager will wait until the sync adapter is not in use before requesting that
* it sync an account's data.
* <li><code>android:isAlwaysSyncable</code> defaults to false and if true tells the SyncManager
- * to intialize the isSyncable state to 1 for that sync adapter for each account that is added.
+ * to initialize the isSyncable state to 1 for that sync adapter for each account that is added.
* <li><code>android:syncAdapterSettingsAction</code> defaults to null and if supplied it
* specifies an Intent action of an activity that can be used to adjust the sync adapter's
* sync settings. The activity must live in the same package as the sync adapter.
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 089cf1098ffc..ed3d4557061e 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -224,7 +224,7 @@ public class ClipData implements Parcelable {
* Create an Item consisting of a single block of (possibly styled) text,
* with an alternative HTML formatted representation. You <em>must</em>
* supply a plain text representation in addition to HTML text; coercion
- * will not be done from HTML formated text into plain text.
+ * will not be done from HTML formatted text into plain text.
*/
public Item(CharSequence text, String htmlText) {
mText = text;
@@ -268,7 +268,7 @@ public class ClipData implements Parcelable {
* Create a complex Item, containing multiple representations of
* text, HTML text, Intent, and/or URI. If providing HTML text, you
* <em>must</em> supply a plain text representation as well; coercion
- * will not be done from HTML formated text into plain text.
+ * will not be done from HTML formatted text into plain text.
*/
public Item(CharSequence text, String htmlText, Intent intent, Uri uri) {
if (htmlText != null && text == null) {
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 7dc45776715c..6a3fa6b2f197 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -637,7 +637,7 @@ public class ContentProviderOperation implements Parcelable {
/**
* The selection and arguments to use. An occurrence of '?' in the selection will be
- * replaced with the corresponding occurence of the selection argument. Any of the
+ * replaced with the corresponding occurrence of the selection argument. Any of the
* selection arguments may be overwritten by a selection argument back reference as
* specified by {@link #withSelectionBackReference}.
* This can only be used with builders of type update, delete, or assert.
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a882434d9d98..c19909da3007 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,7 +1877,7 @@ public abstract class ContentResolver {
* that services the content at uri, starting the provider if necessary. Returns
* null if there is no provider associated wih the uri. The caller must indicate that they are
* done with the provider by calling {@link ContentProviderClient#release} which will allow
- * the system to release the provider it it determines that there is no other reason for
+ * the system to release the provider if it determines that there is no other reason for
* keeping it active.
* @param uri specifies which provider should be acquired
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
@@ -1897,7 +1897,7 @@ public abstract class ContentResolver {
* with the authority of name, starting the provider if necessary. Returns
* null if there is no provider associated wih the uri. The caller must indicate that they are
* done with the provider by calling {@link ContentProviderClient#release} which will allow
- * the system to release the provider it it determines that there is no other reason for
+ * the system to release the provider if it determines that there is no other reason for
* keeping it active.
* @param name specifies which provider should be acquired
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d71157459fc8..31973524ceaf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -187,7 +187,7 @@ public abstract class Context {
*
* <p>This was the legacy (but undocumented) behavior in and
* before Gingerbread (Android 2.3) and this flag is implied when
- * targetting such releases. For applications targetting SDK
+ * targeting such releases. For applications targeting SDK
* versions <em>greater than</em> Android 2.3, this flag must be
* explicitly set if desired.
*
@@ -2840,7 +2840,7 @@ public abstract class Context {
*
* @param service Description of the service to be stopped. The Intent must be either
* fully explicit (supplying a component name) or specify a specific package
- * name it is targetted to.
+ * name it is targeted to.
*
* @return If there is a service matching the given Intent that is already
* running, then it is stopped and {@code true} is returned; else {@code false} is returned.
@@ -4982,6 +4982,14 @@ public abstract class Context {
public abstract Display getDisplay();
/**
+ * Gets the display ID.
+ *
+ * @return display ID associated with this {@link Context}.
+ * @hide
+ */
+ public abstract int getDisplayId();
+
+ /**
* @hide
*/
public abstract void updateDisplay(int displayId);
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index c5dce017430b..bfad2b42bc94 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -921,6 +921,14 @@ public class ContextWrapper extends Context {
* @hide
*/
@Override
+ public int getDisplayId() {
+ return mBase.getDisplayId();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
public void updateDisplay(int displayId) {
mBase.updateDisplay(displayId);
}
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 4e46d5716c7b..4ccafab741d8 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -36,7 +36,7 @@ import java.util.Arrays;
* perform, either through the
* {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
* creating an empty instance with {@link #CursorLoader(Context)} and filling
- * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
+ * in the desired parameters with {@link #setUri(Uri)}, {@link #setSelection(String)},
* {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
* and {@link #setProjection(String[])}.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af910e047341..8913748e0c48 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3955,6 +3955,12 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
/**
+ * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state.
+ * @hide
+ */
+ public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE";
+
+ /**
* The name of the extra used to define the text to be processed, as a
* CharSequence. Note that this may be a styled CharSequence, so you must use
* {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it.
@@ -5523,7 +5529,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* If set and this intent is being used to launch a new activity from an
* existing one, then the reply target of the existing activity will be
- * transfered to the new activity. This way the new activity can call
+ * transferred to the new activity. This way, the new activity can call
* {@link android.app.Activity#setResult} and have that result sent back to
* the reply target of the original activity.
*/
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 0469a9006b25..36d8a3720b5e 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -479,7 +479,7 @@ public class IntentFilter implements Parcelable {
/**
* Modify priority of this filter. This only affects receiver filters.
* The priority of activity filters are set in XML and cannot be changed
- * programatically. The default priority is 0. Positive values will be
+ * programmatically. The default priority is 0. Positive values will be
* before the default, lower values will be after it. Applications should
* use a value that is larger than {@link #SYSTEM_LOW_PRIORITY} and
* smaller than {@link #SYSTEM_HIGH_PRIORITY} .
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5926af6f9082..0a4f4eb8506c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1408,5 +1408,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* @attr ref android.R.styleable#AndroidManifestLayout_minHeight
*/
public final int minHeight;
+
+ /**
+ * Returns if this {@link WindowLayout} has specified bounds.
+ * @hide
+ */
+ public boolean hasSpecifiedSize() {
+ return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
+ }
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 225b6cfd9a8f..c33f143b4cbc 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -236,7 +236,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Value for {@link #flags}: true when the application knows how to
- * accomodate different screen densities. Corresponds to
+ * accommodate different screen densities. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity
* android:anyDensity}.
*/
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6a20c9349e1d..4a4de5160e80 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -43,6 +43,7 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
@@ -273,7 +274,7 @@ interface IPackageManager {
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
- String dialogMessage, String callingPackage, int userId);
+ in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
boolean isPackageSuspendedForUser(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8fab7bb0ad4e..e9cfa78deba6 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -86,6 +86,19 @@ import java.util.List;
* <p>
* The ApiDemos project contains examples of using this API:
* <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
+ * <p>
+ * On Android Q or above, an app installed notification will be posted
+ * by system after a new app is installed.
+ * To customize installer's notification icon, you should declare the following in the manifest
+ * &lt;application> as follows: </p>
+ * <pre>
+ * &lt;meta-data android:name="com.android.packageinstaller.notification.smallIcon"
+ * android:resource="@drawable/installer_notification_icon"/>
+ * </pre>
+ * <pre>
+ * &lt;meta-data android:name="com.android.packageinstaller.notification.color"
+ * android:resource="@color/installer_notification_color"/>
+ * </pre>
*/
public class PackageInstaller {
private static final String TAG = "PackageInstaller";
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 00aa5c291154..cdb781438909 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,10 +16,12 @@
package android.content.pm;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import static android.text.TextUtils.SAFE_STRING_FLAG_FIRST_LINE;
+import static android.text.TextUtils.SAFE_STRING_FLAG_SINGLE_LINE;
+import static android.text.TextUtils.SAFE_STRING_FLAG_TRIM;
+import static android.text.TextUtils.makeSafeForPresentation;
import android.annotation.FloatRange;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.res.XmlResourceParser;
@@ -27,17 +29,13 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.UserHandle;
-import android.text.Html;
-import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.Preconditions;
-import java.lang.annotation.Retention;
import java.text.Collator;
-import java.util.BitSet;
import java.util.Comparator;
/**
@@ -50,9 +48,6 @@ import java.util.Comparator;
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
- private static final int LINE_FEED_CODE_POINT = 10;
- private static final int NBSP_CODE_POINT = 160;
-
/** The maximum length of a safe label, in characters */
private static final int MAX_SAFE_LABEL_LENGTH = 50000;
@@ -60,45 +55,43 @@ public class PackageItemInfo {
public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
/**
- * Flags for {@link #loadSafeLabel(PackageManager, float, int)}
- *
- * @hide
- */
- @Retention(SOURCE)
- @IntDef(flag = true, prefix = "SAFE_LABEL_FLAG_",
- value = {SAFE_LABEL_FLAG_TRIM, SAFE_LABEL_FLAG_SINGLE_LINE,
- SAFE_LABEL_FLAG_FIRST_LINE})
- public @interface SafeLabelFlags {}
-
- /**
* Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges
* of the label.
*
* @see #loadSafeLabel(PackageManager, float, int)
+ *
+ * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_TRIM} instead
* @hide
*/
+ @Deprecated
@SystemApi
- public static final int SAFE_LABEL_FLAG_TRIM = 0x1;
+ public static final int SAFE_LABEL_FLAG_TRIM = SAFE_STRING_FLAG_TRIM;
/**
* Force entire string into single line of text (no newlines). Cannot be set at the same time as
* {@link #SAFE_LABEL_FLAG_FIRST_LINE}.
*
* @see #loadSafeLabel(PackageManager, float, int)
+ *
+ * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_SINGLE_LINE} instead
* @hide
*/
+ @Deprecated
@SystemApi
- public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 0x2;
+ public static final int SAFE_LABEL_FLAG_SINGLE_LINE = SAFE_STRING_FLAG_SINGLE_LINE;
/**
* Return only first line of text (truncate at first newline). Cannot be set at the same time as
* {@link #SAFE_LABEL_FLAG_SINGLE_LINE}.
*
* @see #loadSafeLabel(PackageManager, float, int)
+ *
+ * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_FIRST_LINE} instead
* @hide
*/
+ @Deprecated
@SystemApi
- public static final int SAFE_LABEL_FLAG_FIRST_LINE = 0x4;
+ public static final int SAFE_LABEL_FLAG_FIRST_LINE = SAFE_STRING_FLAG_FIRST_LINE;
private static volatile boolean sForceSafeLabels = false;
@@ -199,8 +192,8 @@ public class PackageItemInfo {
*/
public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) {
if (sForceSafeLabels) {
- return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_LABEL_FLAG_TRIM
- | SAFE_LABEL_FLAG_FIRST_LINE);
+ return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
+ | SAFE_STRING_FLAG_FIRST_LINE);
} else {
return loadUnsafeLabel(pm);
}
@@ -223,16 +216,6 @@ public class PackageItemInfo {
return packageName;
}
- private static boolean isNewline(int codePoint) {
- int type = Character.getType(codePoint);
- return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
- || codePoint == LINE_FEED_CODE_POINT;
- }
-
- private static boolean isWhiteSpace(int codePoint) {
- return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
- }
-
/**
* @hide
* @deprecated use loadSafeLabel(PackageManager, float, int) instead
@@ -240,209 +223,24 @@ public class PackageItemInfo {
@SystemApi
@Deprecated
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
- return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_LABEL_FLAG_TRIM
- | SAFE_LABEL_FLAG_FIRST_LINE);
- }
-
- /**
- * A special string manipulation class. Just records removals and executes the when onString()
- * is called.
- */
- private static class StringWithRemovedChars {
- /** The original string */
- private final String mOriginal;
-
- /**
- * One bit per char in string. If bit is set, character needs to be removed. If whole
- * bit field is not initialized nothing needs to be removed.
- */
- private BitSet mRemovedChars;
-
- StringWithRemovedChars(@NonNull String original) {
- mOriginal = original;
- }
-
- /**
- * Mark all chars in a range {@code [firstRemoved - firstNonRemoved[} (not including
- * firstNonRemoved) as removed.
- */
- void removeRange(int firstRemoved, int firstNonRemoved) {
- if (mRemovedChars == null) {
- mRemovedChars = new BitSet(mOriginal.length());
- }
-
- mRemovedChars.set(firstRemoved, firstNonRemoved);
- }
-
- /**
- * Remove all characters before {@code firstNonRemoved}.
- */
- void removeAllCharBefore(int firstNonRemoved) {
- if (mRemovedChars == null) {
- mRemovedChars = new BitSet(mOriginal.length());
- }
-
- mRemovedChars.set(0, firstNonRemoved);
- }
-
- /**
- * Remove all characters after and including {@code firstRemoved}.
- */
- void removeAllCharAfter(int firstRemoved) {
- if (mRemovedChars == null) {
- mRemovedChars = new BitSet(mOriginal.length());
- }
-
- mRemovedChars.set(firstRemoved, mOriginal.length());
- }
-
- @Override
- public String toString() {
- // Common case, no chars removed
- if (mRemovedChars == null) {
- return mOriginal;
- }
-
- StringBuilder sb = new StringBuilder(mOriginal.length());
- for (int i = 0; i < mOriginal.length(); i++) {
- if (!mRemovedChars.get(i)) {
- sb.append(mOriginal.charAt(i));
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Return length or the original string
- */
- int length() {
- return mOriginal.length();
- }
-
- /**
- * Return if a certain {@code offset} of the original string is removed
- */
- boolean isRemoved(int offset) {
- return mRemovedChars != null && mRemovedChars.get(offset);
- }
-
- /**
- * Return codePoint of original string at a certain {@code offset}
- */
- int codePointAt(int offset) {
- return mOriginal.codePointAt(offset);
- }
+ return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
+ | SAFE_STRING_FLAG_FIRST_LINE);
}
/**
- * Load, clean up and truncate label before use.
- *
- * <p>This method is meant to remove common mistakes and nefarious formatting from strings that
- * are used in sensitive parts of the UI.
- *
- * <p>This method first treats the string like HTML and then ...
- * <ul>
- * <li>Removes new lines or truncates at first new line
- * <li>Trims the white-space off the end
- * <li>Truncates the string to a given length
- * </ul>
- * ... if specified.
- *
- * @param ellipsizeDip Assuming maximum length of the string (in dip), assuming font size 42.
- * This is roughly 50 characters for {@code ellipsizeDip == 1000}.<br />
- * Usually ellipsizing should be left to the view showing the string. If a
- * string is used as an input to another string, it might be useful to
- * control the length of the input string though. {@code 0} disables this
- * feature.
- * @return The safe label
+ * Calls {@link TextUtils#makeSafeForPresentation} for the label of this item.
+ *
+ * <p>For parameters see {@link TextUtils#makeSafeForPresentation}.
+ *
* @hide
- */
+ */
@SystemApi
public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm,
- @FloatRange(from = 0) float ellipsizeDip, @SafeLabelFlags int flags) {
- boolean onlyKeepFirstLine = ((flags & SAFE_LABEL_FLAG_FIRST_LINE) != 0);
- boolean forceSingleLine = ((flags & SAFE_LABEL_FLAG_SINGLE_LINE) != 0);
- boolean trim = ((flags & SAFE_LABEL_FLAG_TRIM) != 0);
-
+ @FloatRange(from = 0) float ellipsizeDip, @TextUtils.SafeStringFlags int flags) {
Preconditions.checkNotNull(pm);
- Preconditions.checkArgument(ellipsizeDip >= 0);
- Preconditions.checkFlagsArgument(flags, SAFE_LABEL_FLAG_TRIM | SAFE_LABEL_FLAG_SINGLE_LINE
- | SAFE_LABEL_FLAG_FIRST_LINE);
- Preconditions.checkArgument(!(onlyKeepFirstLine && forceSingleLine),
- "Cannot set SAFE_LABEL_FLAG_SINGLE_LINE and SAFE_LABEL_FLAG_FIRST_LINE at the same "
- + "time");
-
- // loadLabel() always returns non-null
- String label = loadUnsafeLabel(pm).toString();
-
- // Treat string as HTML. This
- // - converts HTML symbols: e.g. &szlig; -> ß
- // - applies some HTML tags: e.g. <br> -> \n
- // - removes invalid characters such as \b
- // - removes html styling, such as <b>
- // - applies html formatting: e.g. a<p>b</p>c -> a\n\nb\n\nc
- // - replaces some html tags by "object replacement" markers: <img> -> \ufffc
- // - Removes leading white space
- // - Removes all trailing white space beside a single space
- // - Collapses double white space
- StringWithRemovedChars labelStr = new StringWithRemovedChars(
- Html.fromHtml(label).toString());
-
- int firstNonWhiteSpace = -1;
- int firstTrailingWhiteSpace = -1;
-
- // Remove new lines (if requested) and control characters.
- int labelLength = labelStr.length();
- for (int offset = 0; offset < labelLength; ) {
- int codePoint = labelStr.codePointAt(offset);
- int type = Character.getType(codePoint);
- int codePointLen = Character.charCount(codePoint);
- boolean isNewline = isNewline(codePoint);
-
- if (offset > MAX_SAFE_LABEL_LENGTH || onlyKeepFirstLine && isNewline) {
- labelStr.removeAllCharAfter(offset);
- break;
- } else if (forceSingleLine && isNewline) {
- labelStr.removeRange(offset, offset + codePointLen);
- } else if (type == Character.CONTROL && !isNewline) {
- labelStr.removeRange(offset, offset + codePointLen);
- } else if (trim && !isWhiteSpace(codePoint)) {
- // This is only executed if the code point is not removed
- if (firstNonWhiteSpace == -1) {
- firstNonWhiteSpace = offset;
- }
- firstTrailingWhiteSpace = offset + codePointLen;
- }
-
- offset += codePointLen;
- }
-
- if (trim) {
- // Remove leading and trailing white space
- if (firstNonWhiteSpace == -1) {
- // No non whitespace found, remove all
- labelStr.removeAllCharAfter(0);
- } else {
- if (firstNonWhiteSpace > 0) {
- labelStr.removeAllCharBefore(firstNonWhiteSpace);
- }
- if (firstTrailingWhiteSpace < labelLength) {
- labelStr.removeAllCharAfter(firstTrailingWhiteSpace);
- }
- }
- }
- if (ellipsizeDip == 0) {
- return labelStr.toString();
- } else {
- // Truncate
- final TextPaint paint = new TextPaint();
- paint.setTextSize(42);
-
- return TextUtils.ellipsize(labelStr.toString(), paint, ellipsizeDip,
- TextUtils.TruncateAt.END);
- }
+ return makeSafeForPresentation(loadUnsafeLabel(pm).toString(), MAX_SAFE_LABEL_LENGTH,
+ ellipsizeDip, flags);
}
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3032d164ef46..dfb8128e37ee 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5187,6 +5187,7 @@ public abstract class PackageManager {
* @param packageName The name of the package to query
* @throws IllegalArgumentException if the given package name is not installed
*/
+ @Nullable
public abstract String getInstallerPackageName(String packageName);
/**
@@ -5663,7 +5664,7 @@ public abstract class PackageManager {
* {@link Manifest.permission#MANAGE_USERS} to use this api.</p>
*
* @param packageNames The names of the packages to set the suspended status.
- * @param suspended If set to {@code true} than the packages will be suspended, if set to
+ * @param suspended If set to {@code true}, the packages will be suspended, if set to
* {@code false}, the packages will be unsuspended.
* @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
* which will be shared with the apps being suspended. Ignored if
@@ -5675,15 +5676,76 @@ public abstract class PackageManager {
* suspended app.
*
* @return an array of package names for which the suspended status could not be set as
- * requested in this method.
+ * requested in this method. Returns {@code null} if {@code packageNames} was {@code null}.
+ *
+ * @deprecated use {@link #setPackagesSuspended(String[], boolean, PersistableBundle,
+ * PersistableBundle, android.content.pm.SuspendDialogInfo)} instead.
*
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(Manifest.permission.SUSPEND_APPS)
- public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+ @Nullable
+ public String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended,
+ @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
+ @Nullable String dialogMessage) {
+ throw new UnsupportedOperationException("setPackagesSuspended not implemented");
+ }
+
+ /**
+ * Puts the given packages in a suspended state, where attempts at starting activities are
+ * denied.
+ *
+ * <p>The suspended application's notifications and all of its windows will be hidden, any
+ * of its started activities will be stopped and it won't be able to ring the device.
+ * It doesn't remove the data or the actual package file.
+ *
+ * <p>When the user tries to launch a suspended app, a system dialog alerting them that the app
+ * is suspended will be shown instead.
+ * The caller can optionally customize the dialog by passing a {@link SuspendDialogInfo} object
+ * to this api. This dialog will have a button that starts the
+ * {@link Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} intent if the suspending app declares an
+ * activity which handles this action.
+ *
+ * <p>The packages being suspended must already be installed. If a package is uninstalled, it
+ * will no longer be suspended.
+ *
+ * <p>Optionally, the suspending app can provide extra information in the form of
+ * {@link PersistableBundle} objects to be shared with the apps being suspended and the
+ * launcher to support customization that they might need to handle the suspended state.
+ *
+ * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this api.
+ *
+ * @param packageNames The names of the packages to set the suspended status.
+ * @param suspended If set to {@code true}, the packages will be suspended, if set to
+ * {@code false}, the packages will be unsuspended.
+ * @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
+ * which will be shared with the apps being suspended. Ignored if
+ * {@code suspended} is false.
+ * @param launcherExtras An optional {@link PersistableBundle} that the suspending app can
+ * provide which will be shared with the launcher. Ignored if
+ * {@code suspended} is false.
+ * @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
+ * should be shown to the user when they try to launch a suspended app.
+ * Ignored if {@code suspended} is false.
+ *
+ * @return an array of package names for which the suspended status could not be set as
+ * requested in this method. Returns {@code null} if {@code packageNames} was {@code null}.
+ *
+ * @see #isPackageSuspended
+ * @see SuspendDialogInfo
+ * @see SuspendDialogInfo.Builder
+ * @see Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SUSPEND_APPS)
+ @Nullable
+ public String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended,
@Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
- String dialogMessage) {
+ @Nullable SuspendDialogInfo dialogInfo) {
throw new UnsupportedOperationException("setPackagesSuspended not implemented");
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index b5b4432bbdb2..4f58321da2f4 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager.ApplicationInfoFlags;
@@ -205,6 +206,29 @@ public abstract class PackageManagerInternal {
@PackageInfoFlags int flags, int filterCallingUid, int userId);
/**
+ * Return a List of all application packages that are installed on the
+ * device, for a specific user. If flag GET_UNINSTALLED_PACKAGES has been
+ * set, a list of all applications including those deleted with
+ * {@code DONT_DELETE_DATA} (partially installed apps with data directory)
+ * will be returned.
+ *
+ * @param flags Additional option flags to modify the data returned.
+ * @param userId The user for whom the installed applications are to be
+ * listed
+ * @param callingUid The uid of the original caller app
+ * @return A List of ApplicationInfo objects, one for each installed
+ * application. In the unlikely case there are no installed
+ * packages, an empty list is returned. If flag
+ * {@code MATCH_UNINSTALLED_PACKAGES} is set, the application
+ * information is retrieved from the list of uninstalled
+ * applications (which includes installed applications as well as
+ * applications with data directory i.e. applications which had been
+ * deleted with {@code DONT_DELETE_DATA} flag set).
+ */
+ public abstract List<ApplicationInfo> getInstalledApplications(
+ @ApplicationInfoFlags int flags, @UserIdInt int userId, int callingUid);
+
+ /**
* Retrieve launcher extras for a suspended package provided to the system in
* {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
* PersistableBundle, String)}.
@@ -243,14 +267,15 @@ public abstract class PackageManagerInternal {
public abstract String getSuspendingPackage(String suspendedPackage, int userId);
/**
- * Get the dialog message to be shown to the user when they try to launch a suspended
- * application.
+ * Get the information describing the dialog to be shown to the user when they try to launch a
+ * suspended application.
*
* @param suspendedPackage The package that has been suspended.
* @param userId The user for which to check.
- * @return The dialog message to be shown to the user.
+ * @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
*/
- public abstract String getSuspendedDialogMessage(String suspendedPackage, int userId);
+ @Nullable
+ public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId);
/**
* Do a straight uid lookup for the given package/application in the given user.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 24675d301f4a..046e9e7108fd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -47,6 +47,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
+import android.app.AppDetailsActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -2440,17 +2441,17 @@ public class PackageParser {
}
- final int NS = PermissionManager.SPLIT_PERMISSIONS.length;
+ final int NS = PermissionManager.SPLIT_PERMISSIONS.size();
for (int is=0; is<NS; is++) {
final PermissionManager.SplitPermissionInfo spi =
- PermissionManager.SPLIT_PERMISSIONS[is];
+ PermissionManager.SPLIT_PERMISSIONS.get(is);
if (pkg.applicationInfo.targetSdkVersion >= spi.getTargetSdk()
- || !pkg.requestedPermissions.contains(spi.getRootPermission())) {
+ || !pkg.requestedPermissions.contains(spi.getSplitPermission())) {
continue;
}
- final String[] newPerms = spi.getNewPermissions();
- for (int in = 0; in < newPerms.length; in++) {
- final String perm = newPerms[in];
+ final List<String> newPerms = spi.getNewPermissions();
+ for (int in = 0; in < newPerms.size(); in++) {
+ final String perm = newPerms.get(in);
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
}
@@ -3882,6 +3883,11 @@ public class PackageParser {
}
}
+ // Add a hidden app detail activity which forwards user to App Details page.
+ Activity a = generateAppDetailsHiddenActivity(owner, flags, outError,
+ owner.baseHardwareAccelerated);
+ owner.activities.add(a);
+
if (hasActivityOrder) {
Collections.sort(owner.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
}
@@ -4121,9 +4127,14 @@ public class PackageParser {
return false;
}
} else {
- outInfo.name
+ String outInfoName
= buildClassName(owner.applicationInfo.packageName, name, outError);
- if (outInfo.name == null) {
+ if (AppDetailsActivity.class.getName().equals(outInfoName)) {
+ outError[0] = tag + " invalid android:name";
+ return false;
+ }
+ outInfo.name = outInfoName;
+ if (outInfoName == null) {
return false;
}
}
@@ -4162,6 +4173,45 @@ public class PackageParser {
return true;
}
+ /**
+ * Generate activity object that forwards user to App Details page automatically.
+ * This activity should be invisible to user and user should not know or see it.
+ */
+ private @NonNull PackageParser.Activity generateAppDetailsHiddenActivity(
+ PackageParser.Package owner, int flags, String[] outError,
+ boolean hardwareAccelerated) {
+
+ // Build custom App Details activity info instead of parsing it from xml
+ Activity a = new Activity(owner, AppDetailsActivity.class.getName(), new ActivityInfo());
+ a.owner = owner;
+ a.setPackageName(owner.packageName);
+
+ a.info.theme = 0;
+ a.info.exported = true;
+ a.info.name = AppDetailsActivity.class.getName();
+ a.info.processName = owner.applicationInfo.processName;
+ a.info.uiOptions = a.info.applicationInfo.uiOptions;
+ a.info.taskAffinity = buildTaskAffinityName(owner.packageName, owner.packageName,
+ ":app_details", outError);
+ a.info.enabled = true;
+ a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ a.info.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
+ a.info.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
+ a.info.configChanges = getActivityConfigChanges(0, 0);
+ a.info.softInputMode = 0;
+ a.info.persistableMode = ActivityInfo.PERSIST_NEVER;
+ a.info.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+ a.info.lockTaskLaunchMode = 0;
+ a.info.encryptionAware = a.info.directBootAware = false;
+ a.info.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+ a.info.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+ if (hardwareAccelerated) {
+ a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+ }
+ return a;
+ }
+
private Activity parseActivity(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
boolean receiver, boolean hardwareAccelerated)
@@ -7132,10 +7182,16 @@ public class PackageParser {
ComponentName componentName;
String componentShortName;
- public Component(Package _owner) {
- owner = _owner;
- intents = null;
- className = null;
+ public Component(Package owner, ArrayList<II> intents, String className) {
+ this.owner = owner;
+ this.intents = intents;
+ this.className = className;
+ }
+
+ public Component(Package owner) {
+ this.owner = owner;
+ this.intents = null;
+ this.className = null;
}
public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
@@ -7600,6 +7656,13 @@ public class PackageParser {
return mHasMaxAspectRatio;
}
+ // To construct custom activity which does not exist in manifest
+ Activity(final Package owner, final String className, final ActivityInfo info) {
+ super(owner, new ArrayList<>(0), className);
+ this.info = info;
+ this.info.applicationInfo = owner.applicationInfo;
+ }
+
public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
super(args, _info);
info = _info;
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 248d523a78ef..e21c33ad3bc1 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -33,6 +33,7 @@ import android.os.BaseBundle;
import android.os.PersistableBundle;
import android.util.ArraySet;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.util.Arrays;
@@ -50,7 +51,7 @@ public class PackageUserState {
public boolean hidden; // Is the app restricted by owner / admin
public boolean suspended;
public String suspendingPackage;
- public String dialogMessage; // Message to show when a suspended package launch attempt is made
+ public SuspendDialogInfo dialogInfo;
public PersistableBundle suspendedAppExtras;
public PersistableBundle suspendedLauncherExtras;
public boolean instantApp;
@@ -79,6 +80,7 @@ public class PackageUserState {
installReason = PackageManager.INSTALL_REASON_UNKNOWN;
}
+ @VisibleForTesting
public PackageUserState(PackageUserState o) {
ceDataInode = o.ceDataInode;
installed = o.installed;
@@ -87,7 +89,7 @@ public class PackageUserState {
hidden = o.hidden;
suspended = o.suspended;
suspendingPackage = o.suspendingPackage;
- dialogMessage = o.dialogMessage;
+ dialogInfo = o.dialogInfo;
suspendedAppExtras = o.suspendedAppExtras;
suspendedLauncherExtras = o.suspendedLauncherExtras;
instantApp = o.instantApp;
@@ -217,7 +219,7 @@ public class PackageUserState {
|| !suspendingPackage.equals(oldState.suspendingPackage)) {
return false;
}
- if (!Objects.equals(dialogMessage, oldState.dialogMessage)) {
+ if (!Objects.equals(dialogInfo, oldState.dialogInfo)) {
return false;
}
if (!BaseBundle.kindofEquals(suspendedAppExtras,
diff --git a/core/java/android/content/pm/SuspendDialogInfo.aidl b/core/java/android/content/pm/SuspendDialogInfo.aidl
new file mode 100644
index 000000000000..5e711cfb01c2
--- /dev/null
+++ b/core/java/android/content/pm/SuspendDialogInfo.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.pm;
+
+parcelable SuspendDialogInfo;
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
new file mode 100644
index 000000000000..c798c99fed90
--- /dev/null
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -0,0 +1,379 @@
+/*
+ * 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.pm;
+
+import static android.content.res.ResourceId.ID_NULL;
+
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.annotation.SystemApi;
+import android.content.res.ResourceId;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * A container to describe the dialog to be shown when the user tries to launch a suspended
+ * application.
+ * The suspending app can customize the dialog's following attributes:
+ * <ul>
+ * <li>The dialog icon, by providing a resource id.
+ * <li>The title text, by providing a resource id.
+ * <li>The text of the dialog's body, by providing a resource id or a string.
+ * <li>The text on the neutral button which starts the
+ * {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS SHOW_SUSPENDED_APP_DETAILS}
+ * activity, by providing a resource id.
+ * </ul>
+ * System defaults are used whenever any of these are not provided, or any of the provided resource
+ * ids cannot be resolved at the time of displaying the dialog.
+ *
+ * @hide
+ * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+ * SuspendDialogInfo)
+ * @see Builder
+ */
+@SystemApi
+public final class SuspendDialogInfo implements Parcelable {
+ private static final String TAG = SuspendDialogInfo.class.getSimpleName();
+ private static final String XML_ATTR_ICON_RES_ID = "iconResId";
+ private static final String XML_ATTR_TITLE_RES_ID = "titleResId";
+ private static final String XML_ATTR_DIALOG_MESSAGE_RES_ID = "dialogMessageResId";
+ private static final String XML_ATTR_DIALOG_MESSAGE = "dialogMessage";
+ private static final String XML_ATTR_BUTTON_TEXT_RES_ID = "buttonTextResId";
+
+ private final int mIconResId;
+ private final int mTitleResId;
+ private final int mDialogMessageResId;
+ private final String mDialogMessage;
+ private final int mNeutralButtonTextResId;
+
+ /**
+ * @return the resource id of the icon to be used with the dialog
+ * @hide
+ */
+ @DrawableRes
+ public int getIconResId() {
+ return mIconResId;
+ }
+
+ /**
+ * @return the resource id of the title to be used with the dialog
+ * @hide
+ */
+ @StringRes
+ public int getTitleResId() {
+ return mTitleResId;
+ }
+
+ /**
+ * @return the resource id of the text to be shown in the dialog's body
+ * @hide
+ */
+ @StringRes
+ public int getDialogMessageResId() {
+ return mDialogMessageResId;
+ }
+
+ /**
+ * @return the text to be shown in the dialog's body. Returns {@code null} if
+ * {@link #getDialogMessageResId()} returns a valid resource id.
+ * @hide
+ */
+ @Nullable
+ public String getDialogMessage() {
+ return mDialogMessage;
+ }
+
+ /**
+ * @return the text to be shown
+ * @hide
+ */
+ @StringRes
+ public int getNeutralButtonTextResId() {
+ return mNeutralButtonTextResId;
+ }
+
+ /**
+ * @hide
+ */
+ public void saveToXml(XmlSerializer out) throws IOException {
+ if (mIconResId != ID_NULL) {
+ XmlUtils.writeIntAttribute(out, XML_ATTR_ICON_RES_ID, mIconResId);
+ }
+ if (mTitleResId != ID_NULL) {
+ XmlUtils.writeIntAttribute(out, XML_ATTR_TITLE_RES_ID, mTitleResId);
+ }
+ if (mDialogMessageResId != ID_NULL) {
+ XmlUtils.writeIntAttribute(out, XML_ATTR_DIALOG_MESSAGE_RES_ID, mDialogMessageResId);
+ } else {
+ XmlUtils.writeStringAttribute(out, XML_ATTR_DIALOG_MESSAGE, mDialogMessage);
+ }
+ if (mNeutralButtonTextResId != ID_NULL) {
+ XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static SuspendDialogInfo restoreFromXml(XmlPullParser in) {
+ final SuspendDialogInfo.Builder dialogInfoBuilder = new SuspendDialogInfo.Builder();
+ try {
+ final int iconId = XmlUtils.readIntAttribute(in, XML_ATTR_ICON_RES_ID, ID_NULL);
+ final int titleId = XmlUtils.readIntAttribute(in, XML_ATTR_TITLE_RES_ID, ID_NULL);
+ final int buttonTextId = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_TEXT_RES_ID,
+ ID_NULL);
+ final int dialogMessageResId = XmlUtils.readIntAttribute(
+ in, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL);
+ final String dialogMessage = XmlUtils.readStringAttribute(in, XML_ATTR_DIALOG_MESSAGE);
+
+ if (iconId != ID_NULL) {
+ dialogInfoBuilder.setIcon(iconId);
+ }
+ if (titleId != ID_NULL) {
+ dialogInfoBuilder.setTitle(titleId);
+ }
+ if (buttonTextId != ID_NULL) {
+ dialogInfoBuilder.setNeutralButtonText(buttonTextId);
+ }
+ if (dialogMessageResId != ID_NULL) {
+ dialogInfoBuilder.setMessage(dialogMessageResId);
+ } else if (dialogMessage != null) {
+ dialogInfoBuilder.setMessage(dialogMessage);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while parsing from xml. Some fields may default", e);
+ }
+ return dialogInfoBuilder.build();
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = mIconResId;
+ hashCode = 31 * hashCode + mTitleResId;
+ hashCode = 31 * hashCode + mNeutralButtonTextResId;
+ hashCode = 31 * hashCode + mDialogMessageResId;
+ hashCode = 31 * hashCode + Objects.hashCode(mDialogMessage);
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SuspendDialogInfo)) {
+ return false;
+ }
+ final SuspendDialogInfo otherDialogInfo = (SuspendDialogInfo) obj;
+ return mIconResId == otherDialogInfo.mIconResId
+ && mTitleResId == otherDialogInfo.mTitleResId
+ && mDialogMessageResId == otherDialogInfo.mDialogMessageResId
+ && mNeutralButtonTextResId == otherDialogInfo.mNeutralButtonTextResId
+ && Objects.equals(mDialogMessage, otherDialogInfo.mDialogMessage);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder("SuspendDialogInfo: {");
+ if (mIconResId != ID_NULL) {
+ builder.append("mIconId = 0x");
+ builder.append(Integer.toHexString(mIconResId));
+ builder.append(" ");
+ }
+ if (mTitleResId != ID_NULL) {
+ builder.append("mTitleResId = 0x");
+ builder.append(Integer.toHexString(mTitleResId));
+ builder.append(" ");
+ }
+ if (mNeutralButtonTextResId != ID_NULL) {
+ builder.append("mNeutralButtonTextResId = 0x");
+ builder.append(Integer.toHexString(mNeutralButtonTextResId));
+ builder.append(" ");
+ }
+ if (mDialogMessageResId != ID_NULL) {
+ builder.append("mDialogMessageResId = 0x");
+ builder.append(Integer.toHexString(mDialogMessageResId));
+ builder.append(" ");
+ } else if (mDialogMessage != null) {
+ builder.append("mDialogMessage = \"");
+ builder.append(mDialogMessage);
+ builder.append("\" ");
+ }
+ builder.append("}");
+ return builder.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeInt(mIconResId);
+ dest.writeInt(mTitleResId);
+ dest.writeInt(mDialogMessageResId);
+ dest.writeString(mDialogMessage);
+ dest.writeInt(mNeutralButtonTextResId);
+ }
+
+ private SuspendDialogInfo(Parcel source) {
+ mIconResId = source.readInt();
+ mTitleResId = source.readInt();
+ mDialogMessageResId = source.readInt();
+ mDialogMessage = source.readString();
+ mNeutralButtonTextResId = source.readInt();
+ }
+
+ SuspendDialogInfo(Builder b) {
+ mIconResId = b.mIconResId;
+ mTitleResId = b.mTitleResId;
+ mDialogMessageResId = b.mDialogMessageResId;
+ mDialogMessage = (mDialogMessageResId == ID_NULL) ? b.mDialogMessage : null;
+ mNeutralButtonTextResId = b.mNeutralButtonTextResId;
+ }
+
+ public static final Creator<SuspendDialogInfo> CREATOR = new Creator<SuspendDialogInfo>() {
+ @Override
+ public SuspendDialogInfo createFromParcel(Parcel source) {
+ return new SuspendDialogInfo(source);
+ }
+
+ @Override
+ public SuspendDialogInfo[] newArray(int size) {
+ return new SuspendDialogInfo[size];
+ }
+ };
+
+ /**
+ * Builder to build a {@link SuspendDialogInfo} object.
+ */
+ public static final class Builder {
+ private int mDialogMessageResId = ID_NULL;
+ private String mDialogMessage;
+ private int mTitleResId = ID_NULL;
+ private int mIconResId = ID_NULL;
+ private int mNeutralButtonTextResId = ID_NULL;
+
+ /**
+ * Set the resource id of the icon to be used. If not provided, no icon will be shown.
+ *
+ * @param resId The resource id of the icon.
+ * @return this builder object.
+ */
+ @NonNull
+ public Builder setIcon(@DrawableRes int resId) {
+ Preconditions.checkArgument(ResourceId.isValid(resId), "Invalid resource id provided");
+ mIconResId = resId;
+ return this;
+ }
+
+ /**
+ * Set the resource id of the title text to be displayed. If this is not provided, the
+ * system will use a default title.
+ *
+ * @param resId The resource id of the title.
+ * @return this builder object.
+ */
+ @NonNull
+ public Builder setTitle(@StringRes int resId) {
+ Preconditions.checkArgument(ResourceId.isValid(resId), "Invalid resource id provided");
+ mTitleResId = resId;
+ return this;
+ }
+
+ /**
+ * Set the text to show in the body of the dialog. Ignored if a resource id is set via
+ * {@link #setMessage(int)}.
+ * <p>
+ * The system will use {@link String#format(Locale, String, Object...) String.format} to
+ * insert the suspended app name into the message, so an example format string could be
+ * {@code "The app %1$s is currently suspended"}. This is optional - if the string passed in
+ * {@code message} does not accept an argument, it will be used as is.
+ *
+ * @param message The dialog message.
+ * @return this builder object.
+ * @see #setMessage(int)
+ */
+ @NonNull
+ public Builder setMessage(@NonNull String message) {
+ Preconditions.checkStringNotEmpty(message, "Message cannot be null or empty");
+ mDialogMessage = message;
+ return this;
+ }
+
+ /**
+ * Set the resource id of the dialog message to be shown. If no dialog message is provided
+ * via either this method or {@link #setMessage(String)}, the system will use a
+ * default message.
+ * <p>
+ * The system will use {@link android.content.res.Resources#getString(int, Object...)
+ * getString} to insert the suspended app name into the message, so an example format string
+ * could be {@code "The app %1$s is currently suspended"}. This is optional - if the string
+ * referred to by {@code resId} does not accept an argument, it will be used as is.
+ *
+ * @param resId The resource id of the dialog message.
+ * @return this builder object.
+ * @see #setMessage(String)
+ */
+ @NonNull
+ public Builder setMessage(@StringRes int resId) {
+ Preconditions.checkArgument(ResourceId.isValid(resId), "Invalid resource id provided");
+ mDialogMessageResId = resId;
+ return this;
+ }
+
+ /**
+ * Set the resource id of text to be shown on the neutral button. Tapping this button starts
+ * the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. If this is
+ * not provided, the system will use a default text.
+ *
+ * @param resId The resource id of the button text
+ * @return this builder object.
+ */
+ @NonNull
+ public Builder setNeutralButtonText(@StringRes int resId) {
+ Preconditions.checkArgument(ResourceId.isValid(resId), "Invalid resource id provided");
+ mNeutralButtonTextResId = resId;
+ return this;
+ }
+
+ /**
+ * Build the final object based on given inputs.
+ *
+ * @return The {@link SuspendDialogInfo} object built using this builder.
+ */
+ @NonNull
+ public SuspendDialogInfo build() {
+ return new SuspendDialogInfo(this);
+ }
+ }
+}
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 8f8f67625a33..42e7ac7e8431 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -53,7 +53,7 @@ public final class SQLiteStatement extends SQLiteProgram {
}
/**
- * Execute this SQL statement, if the the number of rows affected by execution of this SQL
+ * Execute this SQL statement, if the number of rows affected by execution of this SQL
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
*
* @return the number of rows affected by this SQL statement execution.
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index 1734b41675e4..79e15a7a9a2d 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -201,11 +201,22 @@ public interface BiometricAuthenticator {
throw new UnsupportedOperationException("Stub!");
}
+ /**
+ * @return true if the user has enrolled templates for this biometric.
+ */
default boolean hasEnrolledTemplates(int userId) {
throw new UnsupportedOperationException("Stub!");
}
/**
+ * Sets the active user. This is meant to be used to select the current profile
+ * to allow separate templates for work profile.
+ */
+ default void setActiveUser(int userId) {
+ throw new UnsupportedOperationException("Stub!");
+ }
+
+ /**
* This call warms up the hardware and starts scanning for valid biometrics. It terminates
* when {@link AuthenticationCallback#onAuthenticationError(int,
* CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 0faecb03d4fc..1d400018d60c 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -107,4 +107,22 @@ public class BiometricManager {
Slog.w(TAG, "registerEnabledOnKeyguardCallback(): Service not connected");
}
}
+
+ /**
+ * Sets the active user.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void setActiveUser(int userId) {
+ if (mService != null) {
+ try {
+ mService.setActiveUser(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "setActiveUser(): Service not connected");
+ }
+ }
}
+
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 83998cc1c66a..7952c4104d1f 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -17,6 +17,7 @@
package android.hardware.biometrics;
import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
@@ -55,6 +56,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
/**
* @hide
*/
+ public static final String KEY_USE_DEFAULT_TITLE = "use_default_title";
+ /**
+ * @hide
+ */
public static final String KEY_SUBTITLE = "subtitle";
/**
* @hide
@@ -131,6 +136,17 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
+ * For internal use currently. Only takes effect if title is null/empty. Shows a default
+ * modality-specific title.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public Builder setUseDefaultTitle() {
+ mBundle.putBoolean(KEY_USE_DEFAULT_TITLE, true);
+ return this;
+ }
+
+ /**
* Optional: Set the subtitle to display.
* @param subtitle
* @return
@@ -206,8 +222,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
public BiometricPrompt build() {
final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
+ final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
- if (TextUtils.isEmpty(title)) {
+ if (TextUtils.isEmpty(title) && !useDefaultTitle) {
throw new IllegalArgumentException("Title must be set and non-empty");
} else if (TextUtils.isEmpty(negative)) {
throw new IllegalArgumentException("Negative text must be set and non-empty");
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 51e4ecbf56b0..e17feff0160a 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -43,4 +43,7 @@ interface IBiometricService {
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
-} \ No newline at end of file
+
+ // Explicitly set the active user.
+ void setActiveUser(int userId);
+}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 486b054e1c00..d4dc181e5eec 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2090,7 +2090,7 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 09113e5d175d..01ef58e987d7 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -397,7 +397,7 @@ public final class DisplayManager {
if (display == null) {
// TODO: We cannot currently provide any override configurations for metrics on displays
// other than the display the context is associated with.
- final Context context = mContext.getDisplay().getDisplayId() == displayId
+ final Context context = mContext.getDisplayId() == displayId
? mContext : mContext.getApplicationContext();
display = mGlobal.getCompatibleDisplay(displayId, context.getResources());
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 7aec43ed4ca2..536c4a51db62 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -317,6 +317,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
+ @Override
public void setActiveUser(int userId) {
if (mService != null) {
try {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index bf2280d5c39a..bb9821169a54 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -521,6 +521,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
+ @Override
public void setActiveUser(int userId) {
if (mService != null) try {
mService.setActiveUser(userId);
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 917644db4202..6609b76faac1 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -133,6 +133,7 @@ public class ContextHubClient implements Closeable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) {
// TODO: Implement this
return false;
@@ -146,6 +147,7 @@ public class ContextHubClient implements Closeable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean unregisterIntent(@NonNull PendingIntent intent) {
// TODO: Implement this
return false;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 36f3586aec2a..f94d69b7fa2d 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -749,6 +749,7 @@ public final class ContextHubManager {
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
@@ -785,6 +786,7 @@ public final class ContextHubManager {
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
@@ -811,6 +813,7 @@ public final class ContextHubManager {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback,
@@ -835,6 +838,7 @@ public final class ContextHubManager {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8333b817add0..1fbfa40d5d64 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -83,6 +83,7 @@ import java.util.Map;
@SystemService(Context.CONNECTIVITY_SERVICE)
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* A change in network connectivity has occurred. A default connection has either
@@ -2493,6 +2494,7 @@ public class ConnectivityManager {
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
+ printStackTrace();
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
@@ -2513,6 +2515,7 @@ public class ConnectivityManager {
*/
@Deprecated
public void reportBadNetwork(Network network) {
+ printStackTrace();
try {
// One of these will be ignored because it matches system's current state.
// The other will trigger the necessary reevaluation.
@@ -2535,6 +2538,7 @@ public class ConnectivityManager {
* Internet using {@code network} or {@code false} if not.
*/
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ printStackTrace();
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
@@ -2727,8 +2731,11 @@ public class ConnectivityManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
- @UnsupportedAppUsage
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK})
+ @SystemApi
public void setAirplaneMode(boolean enable) {
try {
mService.setAirplaneMode(enable);
@@ -3073,6 +3080,7 @@ public class ConnectivityManager {
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+ printStackTrace();
checkCallbackNotNull(callback);
Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
final NetworkRequest request;
@@ -3332,6 +3340,7 @@ public class ConnectivityManager {
* {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
@@ -3355,6 +3364,7 @@ public class ConnectivityManager {
* corresponding NetworkRequest you'd like to remove. Cannot be null.
*/
public void releaseNetworkRequest(PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.releasePendingNetworkRequest(operation);
@@ -3439,6 +3449,7 @@ public class ConnectivityManager {
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(request.networkCapabilities, operation);
@@ -3520,6 +3531,7 @@ public class ConnectivityManager {
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ printStackTrace();
checkCallbackNotNull(networkCallback);
final List<NetworkRequest> reqs = new ArrayList<>();
// Find all requests associated to this callback and stop callback triggers immediately.
@@ -3948,4 +3960,19 @@ public class ConnectivityManager {
throw e.rethrowFromSystemServer();
}
}
+
+ private void printStackTrace() {
+ if (DEBUG) {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 3; i < callStack.length; i++) {
+ final String stackTrace = callStack[i].toString();
+ if (stackTrace == null || stackTrace.contains("android.os")) {
+ break;
+ }
+ sb.append(" [").append(stackTrace).append("]");
+ }
+ Log.d(TAG, "StackLog:" + sb.toString());
+ }
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8681893702b4..412a700de65b 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,9 +17,12 @@
package android.os;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.ActivityThread;
import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
@@ -127,14 +130,21 @@ public class Build {
* <a href="/training/articles/security-key-attestation.html">key attestation</a> to obtain
* proof of the device's original identifiers.
*
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. Profile owner access is deprecated and will be removed in a future
+ * release.
+ *
* @return The serial number if specified.
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static String getSerial() {
IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
.asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
try {
- return service.getSerial();
+ Application application = ActivityThread.currentApplication();
+ String callingPackage = application != null ? application.getPackageName() : null;
+ return service.getSerialForPackage(callingPackage);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -1103,19 +1113,37 @@ public class Build {
}
/** The name of this partition, e.g. "system", or "vendor" */
+ @NonNull
public String getName() {
return mName;
}
/** The build fingerprint of this partition, see {@link Build#FINGERPRINT}. */
+ @NonNull
public String getFingerprint() {
return mFingerprint;
}
/** The time (ms since epoch), at which this partition was built, see {@link Build#TIME}. */
- public long getTimeMillis() {
+ public long getBuildTimeMillis() {
return mTimeMs;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Partition)) {
+ return false;
+ }
+ Partition op = (Partition) o;
+ return mName.equals(op.mName)
+ && mFingerprint.equals(op.mFingerprint)
+ && mTimeMs == op.mTimeMs;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mFingerprint, mTimeMs);
+ }
}
/**
@@ -1124,7 +1152,8 @@ public class Build {
* The list includes partitions that are suitable candidates for over-the-air updates. This is
* not an exhaustive list of partitions on the device.
*/
- public static List<Partition> getPartitions() {
+ @NonNull
+ public static List<Partition> getFingerprintedPartitions() {
ArrayList<Partition> partitions = new ArrayList();
String[] names = new String[] {
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
new file mode 100644
index 000000000000..53037b2499cd
--- /dev/null
+++ b/core/java/android/os/DumpstateOptions.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+/**
+ * Options passed to dumpstate service.
+ *
+ * @hide
+ */
+public final class DumpstateOptions implements Parcelable {
+ // If true the caller can get callbacks with per-section
+ // progress details.
+ private final boolean mGetSectionDetails;
+ // Name of the caller.
+ private final String mName;
+
+ public DumpstateOptions(Parcel in) {
+ mGetSectionDetails = in.readBoolean();
+ mName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mGetSectionDetails);
+ out.writeString(mName);
+ }
+
+ public static final Parcelable.Creator<DumpstateOptions> CREATOR =
+ new Parcelable.Creator<DumpstateOptions>() {
+ public DumpstateOptions createFromParcel(Parcel in) {
+ return new DumpstateOptions(in);
+ }
+
+ public DumpstateOptions[] newArray(int size) {
+ return new DumpstateOptions[size];
+ }
+ };
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 54be6393e651..df3aae2c901c 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -54,9 +54,9 @@ public class GraphicsEnvironment {
/**
* Set up GraphicsEnvironment
*/
- public void setup(Context context) {
- setupGpuLayers(context);
- setupAngle(context);
+ public void setup(Context context, Bundle coreSettings) {
+ setupGpuLayers(context, coreSettings);
+ setupAngle(context, coreSettings);
chooseDriver(context);
}
@@ -81,27 +81,54 @@ public class GraphicsEnvironment {
}
/**
+ * Return the debug layer app's on-disk and in-APK lib directories
+ */
+ private static String getDebugLayerAppPaths(Context context, String app) {
+ ApplicationInfo appInfo;
+ try {
+ appInfo = context.getPackageManager().getApplicationInfo(
+ app, PackageManager.MATCH_ALL);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Debug layer app '" + app + "' not installed");
+
+ return null;
+ }
+
+ String abi = chooseAbi(appInfo);
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(appInfo.nativeLibraryDir)
+ .append(File.pathSeparator);
+ sb.append(appInfo.sourceDir)
+ .append("!/lib/")
+ .append(abi);
+ String paths = sb.toString();
+
+ if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
+
+ return paths;
+ }
+
+ /**
* Set up layer search paths for all apps
* If debuggable, check for additional debug settings
*/
- private void setupGpuLayers(Context context) {
+ private void setupGpuLayers(Context context, Bundle coreSettings) {
String layerPaths = "";
// Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable
+ // 1. App is debuggable or device is rooted
// 2. ENABLE_GPU_DEBUG_LAYERS is true
// 3. Package name is equal to GPU_DEBUG_APP
- if (isDebuggable(context)) {
+ if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
- int enable = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
if (enable != 0) {
- String gpuDebugApp = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.GPU_DEBUG_APP);
+ String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
String packageName = context.getPackageName();
@@ -115,8 +142,22 @@ public class GraphicsEnvironment {
// the layers specified by the app.
layerPaths = mDebugLayerPath + ":";
- String layers = Settings.Global.getString(context.getContentResolver(),
- Settings.Global.GPU_DEBUG_LAYERS);
+
+ // If there is a debug layer app specified, add its path.
+ String gpuDebugLayerApp =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
+
+ if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
+ Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
+ String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
+ if (paths != null) {
+ // Append the path so files placed in the app's base directory will
+ // override the external path
+ layerPaths += paths + ":";
+ }
+ }
+
+ String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
Log.i(TAG, "Debug layer list: " + layers);
if (layers != null && !layers.isEmpty()) {
@@ -135,11 +176,10 @@ public class GraphicsEnvironment {
/**
* Pass ANGLE details down to trigger enable logic
*/
- private static void setupAngle(Context context) {
+ private static void setupAngle(Context context, Bundle coreSettings) {
String angleEnabledApp =
- Settings.Global.getString(context.getContentResolver(),
- Settings.Global.ANGLE_ENABLED_APP);
+ coreSettings.getString(Settings.Global.ANGLE_ENABLED_APP);
String packageName = context.getPackageName();
@@ -291,6 +331,7 @@ public class GraphicsEnvironment {
return null;
}
+ private static native int getCanLoadSystemLibraries();
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDriverPath(String path);
diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
index ac19f2bd5bbc..87d358f50e74 100644
--- a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
+++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
@@ -21,4 +21,5 @@ package android.os;
*/
interface IDeviceIdentifiersPolicyService {
String getSerial();
+ String getSerialForPackage(in String callingPackage);
} \ No newline at end of file
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 20ca19bc04aa..c9c42058bad0 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -388,10 +388,10 @@ interface INetworkManagementService
/**
* Setup a new physical network.
- * @param permission null if no permissions required to access this network. PERMISSION_NETWORK
- * or PERMISSION_SYSTEM to set respective permission.
+ * @param permission PERMISSION_NONE if no permissions required to access this network.
+ * PERMISSION_NETWORK or PERMISSION_SYSTEM to set respective permission.
*/
- void createPhysicalNetwork(int netId, String permission);
+ void createPhysicalNetwork(int netId, int permission);
/**
* Setup a new VPN.
@@ -420,10 +420,10 @@ interface INetworkManagementService
/**
* Set permission for a network.
- * @param permission null to clear permissions. PERMISSION_NETWORK or PERMISSION_SYSTEM to set
- * permission.
+ * @param permission PERMISSION_NONE to clear permissions.
+ * PERMISSION_NETWORK or PERMISSION_SYSTEM to set permission.
*/
- void setNetworkPermission(int netId, String permission);
+ void setNetworkPermission(int netId, int permission);
void setPermission(String permission, in int[] uids);
void clearPermission(in int[] uids);
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index cd3f301ebf08..5d5e5e233b35 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,8 @@ package android.os;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
*
* Defines a message containing a description and arbitrary data object that can be
@@ -111,7 +113,13 @@ public final class Message implements Parcelable {
/*package*/ int flags;
- /*package*/ long when;
+ /**
+ * The targeted delivery time of this message. The time-base is
+ * {@link SystemClock#uptimeMillis}.
+ * @hide Only for use within the tests.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public long when;
/*package*/ Bundle data;
@@ -382,7 +390,7 @@ public final class Message implements Parcelable {
* the <em>target</em> {@link Handler} that is receiving this Message to
* dispatch it. If
* not set, the message will be dispatched to the receiving Handler's
- * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+ * {@link Handler#handleMessage(Message)}.
*/
public Runnable getCallback() {
return callback;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 4fe2d58ff75f..f8feb7b4a693 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -61,7 +61,6 @@ public final class UserHandle implements Parcelable {
public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
/** @hide An undefined user id */
- @SystemApi
public static final @UserIdInt int USER_NULL = -10000;
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 128217001b17..7ea20082e660 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -268,7 +268,7 @@ public class UserManager {
public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
/**
- * This restriction is a device-wide version of {@link DISALLOW_INSTALL_UNKNOWN_SOURCES}.
+ * This restriction is a device-wide version of {@link #DISALLOW_INSTALL_UNKNOWN_SOURCES}.
*
* Specifies if all users on the device are disallowed from enabling the
* "Unknown Sources" setting, that allows installation of apps from unknown sources.
@@ -2363,7 +2363,6 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS}, conditional = true)
- @SystemApi
public @NonNull int[] getProfileIds(@UserIdInt int userId, boolean enabledOnly) {
try {
return mService.getProfileIds(userId, enabledOnly);
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 1f54ea53facc..63ff7b22f364 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -16,6 +16,9 @@
package android.os.storage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* Mount service local interface.
*
@@ -81,18 +84,26 @@ public abstract class StorageManagerInternal {
public abstract int getExternalStorageMountMode(int uid, String packageName);
/**
- * Mount external storage for the given package.
+ * Create storage sandbox for the given package.
*
* <p> This will involve calling into vold to setup appropriate bind mounts.
*
- * @param packageName The package for which external storage will be mounted.
+ * @param packageName The package for which the sandbox needs to be created.
* @param appId The appId for the given package.
* @param sharedUserId The sharedUserId for given package if it specified
* {@code android:sharedUserId} in the manifest, otherwise {@code null}
- * @param userId The userId in which the storage needs to be mounted.
+ * @param userId The userId in which the sandbox needs to be created.
+ */
+ public abstract void prepareSandboxForApp(@NonNull String packageName, int appId,
+ @Nullable String sharedUserId, int userId);
+
+ /**
+ * Delete storage sandbox for the given package.
+ *
+ * @param packageName The package for which the sandbox needs to be destroyed.
+ * @param userId The userId in which the sandbox needs to be destroyed.
*/
- public abstract void mountExternalStorageForApp(String packageName, int appId,
- String sharedUserId, int userId);
+ public abstract void destroySandboxForApp(@NonNull String packageName, int userId);
/**
* @return Labels of storage volumes that are visible to the given userId.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index aa44eb7e3a26..7ffb22f189b8 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -25,7 +25,9 @@ import android.content.Context;
import com.android.internal.annotations.Immutable;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* System level service for accessing the permission capabilities of the platform.
@@ -40,26 +42,28 @@ public final class PermissionManager {
*
* @hide
*/
- public static final SplitPermissionInfo[] SPLIT_PERMISSIONS = new SplitPermissionInfo[]{
+ public static final List<SplitPermissionInfo> SPLIT_PERMISSIONS = Arrays.asList(
// READ_EXTERNAL_STORAGE is always required when an app requests
// WRITE_EXTERNAL_STORAGE, because we can't have an app that has
// write access without read access. The hack here with the target
// target SDK version ensures that this grant is always done.
new SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
+ Collections.singletonList(android.Manifest.permission.READ_EXTERNAL_STORAGE),
android.os.Build.VERSION_CODES.CUR_DEVELOPMENT + 1),
new SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
- new String[]{android.Manifest.permission.READ_CALL_LOG},
+ Collections.singletonList(android.Manifest.permission.READ_CALL_LOG),
android.os.Build.VERSION_CODES.JELLY_BEAN),
new SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
- new String[]{android.Manifest.permission.WRITE_CALL_LOG},
+ Collections.singletonList(android.Manifest.permission.WRITE_CALL_LOG),
android.os.Build.VERSION_CODES.JELLY_BEAN),
new SplitPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION,
- new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+ Collections.singletonList(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
android.os.Build.VERSION_CODES.P0),
new SplitPermissionInfo(Manifest.permission.ACCESS_COARSE_LOCATION,
- new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
- android.os.Build.VERSION_CODES.P0)};
+ Collections.singletonList(
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
+ android.os.Build.VERSION_CODES.P0));
private final @NonNull Context mContext;
@@ -74,7 +78,7 @@ public final class PermissionManager {
}
/**
- * Get list of permissions that have been split into more granular or dependent permissions.
+ * Get set of permissions that have been split into more granular or dependent permissions.
*
* <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
* {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
@@ -82,7 +86,7 @@ public final class PermissionManager {
* the location permission only grants location access while the app is in foreground. This
* would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
* such an old app asks for a location permission (i.e. the
- * {@link SplitPermissionInfo#getRootPermission()}), then the
+ * {@link SplitPermissionInfo#getSplitPermission()}), then the
* {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
* {@{@link SplitPermissionInfo#getNewPermissions}) is added.
*
@@ -91,8 +95,9 @@ public final class PermissionManager {
*
* @return All permissions that are split.
*/
- public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
- return Arrays.asList(SPLIT_PERMISSIONS);
+ public @NonNull
+ List<SplitPermissionInfo> getSplitPermissions() {
+ return SPLIT_PERMISSIONS;
}
/**
@@ -101,21 +106,35 @@ public final class PermissionManager {
*/
@Immutable
public static final class SplitPermissionInfo {
- private final @NonNull String mRootPerm;
- private final @NonNull String[] mNewPerms;
+ private final @NonNull String mSplitPerm;
+ private final @NonNull List<String> mNewPerms;
private final int mTargetSdk;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SplitPermissionInfo that = (SplitPermissionInfo) o;
+ return mTargetSdk == that.mTargetSdk
+ && Objects.equals(mSplitPerm, that.mSplitPerm);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSplitPerm, mTargetSdk);
+ }
+
/**
* Get the permission that is split.
*/
- public @NonNull String getRootPermission() {
- return mRootPerm;
+ public @NonNull String getSplitPermission() {
+ return mSplitPerm;
}
/**
* Get the permissions that are added.
*/
- public @NonNull String[] getNewPermissions() {
+ public @NonNull List<String> getNewPermissions() {
return mNewPerms;
}
@@ -126,9 +145,9 @@ public final class PermissionManager {
return mTargetSdk;
}
- private SplitPermissionInfo(@NonNull String rootPerm, @NonNull String[] newPerms,
+ private SplitPermissionInfo(@NonNull String rootPerm, @NonNull List<String> newPerms,
int targetSdk) {
- mRootPerm = rootPerm;
+ mSplitPerm = rootPerm;
mNewPerms = newPerms;
mTargetSdk = targetSdk;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9bc17f22bc27..c6e457436025 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7375,6 +7375,15 @@ public final class Settings {
public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application";
/**
+ * Specifies the package name currently configured to be the default application to perform
+ * the user-defined call redirection service with Telecom.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static final String CALL_REDIRECTION_DEFAULT_APPLICATION =
+ "call_redirection_default_application";
+
+ /**
* Specifies the package name currently configured to be the emergency assistance application
*
* @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
@@ -11622,6 +11631,12 @@ public final class Settings {
public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers";
/**
+ * Addition app for GPU layer discovery
+ * @hide
+ */
+ public static final String GPU_DEBUG_LAYER_APP = "gpu_debug_layer_app";
+
+ /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated This functionality is no longer available as of
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index b461c0daaca5..7af9db8ebf32 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -405,8 +405,8 @@ public abstract class TextClassifierService extends Service {
PackageManager.MATCH_SYSTEM_ONLY);
if ((ri == null) || (ri.serviceInfo == null)) {
- Slog.w(LOG_TAG, String.format("Package or service not found in package %s",
- packageName));
+ Slog.w(LOG_TAG, String.format("Package or service not found in package %s for user %d",
+ packageName, context.getUserId()));
return null;
}
final ServiceInfo si = ri.serviceInfo;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index c89617fefec5..0808cdd6aedb 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -23,6 +23,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.text.LineBreaker;
import android.text.method.TextKeyListener;
import android.text.style.AlignmentSpan;
import android.text.style.LeadingMarginSpan;
@@ -50,9 +51,9 @@ import java.util.Arrays;
public abstract class Layout {
/** @hide */
@IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
- NativeLineBreaker.BREAK_STRATEGY_SIMPLE,
- NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY,
- NativeLineBreaker.BREAK_STRATEGY_BALANCED
+ LineBreaker.BREAK_STRATEGY_SIMPLE,
+ LineBreaker.BREAK_STRATEGY_HIGH_QUALITY,
+ LineBreaker.BREAK_STRATEGY_BALANCED
})
@Retention(RetentionPolicy.SOURCE)
public @interface BreakStrategy {}
@@ -63,20 +64,19 @@ public abstract class Layout {
* before it (which yields a more consistent user experience when editing), but layout may not
* be the highest quality.
*/
- public static final int BREAK_STRATEGY_SIMPLE = NativeLineBreaker.BREAK_STRATEGY_SIMPLE;
+ public static final int BREAK_STRATEGY_SIMPLE = LineBreaker.BREAK_STRATEGY_SIMPLE;
/**
* Value for break strategy indicating high quality line breaking, including automatic
* hyphenation and doing whole-paragraph optimization of line breaks.
*/
- public static final int BREAK_STRATEGY_HIGH_QUALITY =
- NativeLineBreaker.BREAK_STRATEGY_HIGH_QUALITY;
+ public static final int BREAK_STRATEGY_HIGH_QUALITY = LineBreaker.BREAK_STRATEGY_HIGH_QUALITY;
/**
* Value for break strategy indicating balanced line breaking. The breaks are chosen to
* make all lines as close to the same length as possible, including automatic hyphenation.
*/
- public static final int BREAK_STRATEGY_BALANCED = NativeLineBreaker.BREAK_STRATEGY_BALANCED;
+ public static final int BREAK_STRATEGY_BALANCED = LineBreaker.BREAK_STRATEGY_BALANCED;
/** @hide */
@IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
@@ -94,32 +94,29 @@ public abstract class Layout {
* layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
* as suggestions for potential line breaks.
*/
- public static final int HYPHENATION_FREQUENCY_NONE =
- NativeLineBreaker.HYPHENATION_FREQUENCY_NONE;
+ public static final int HYPHENATION_FREQUENCY_NONE = LineBreaker.HYPHENATION_FREQUENCY_NONE;
/**
* Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
* is a conservative default. Useful for informal cases, such as short sentences or chat
* messages.
*/
- public static final int HYPHENATION_FREQUENCY_NORMAL =
- NativeLineBreaker.HYPHENATION_FREQUENCY_NORMAL;
+ public static final int HYPHENATION_FREQUENCY_NORMAL = LineBreaker.HYPHENATION_FREQUENCY_NORMAL;
/**
* Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
* in typography. Useful for running text and where it's important to put the maximum amount of
* text in a screen with limited space.
*/
- public static final int HYPHENATION_FREQUENCY_FULL =
- NativeLineBreaker.HYPHENATION_FREQUENCY_FULL;
+ public static final int HYPHENATION_FREQUENCY_FULL = LineBreaker.HYPHENATION_FREQUENCY_FULL;
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
/** @hide */
@IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = {
- NativeLineBreaker.JUSTIFICATION_MODE_NONE,
- NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD
+ LineBreaker.JUSTIFICATION_MODE_NONE,
+ LineBreaker.JUSTIFICATION_MODE_INTER_WORD
})
@Retention(RetentionPolicy.SOURCE)
public @interface JustificationMode {}
@@ -127,13 +124,13 @@ public abstract class Layout {
/**
* Value for justification mode indicating no justification.
*/
- public static final int JUSTIFICATION_MODE_NONE = NativeLineBreaker.JUSTIFICATION_MODE_NONE;
+ public static final int JUSTIFICATION_MODE_NONE = LineBreaker.JUSTIFICATION_MODE_NONE;
/**
* Value for justification mode indicating the text is justified by stretching word spacing.
*/
public static final int JUSTIFICATION_MODE_INTER_WORD =
- NativeLineBreaker.JUSTIFICATION_MODE_INTER_WORD;
+ LineBreaker.JUSTIFICATION_MODE_INTER_WORD;
/*
* Line spacing multiplier for default line spacing.
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 9bf8cd20f441..0a2d65c9ebff 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.text.MeasuredText;
import android.text.AutoGrowArray.ByteArray;
import android.text.AutoGrowArray.FloatArray;
import android.text.AutoGrowArray.IntArray;
@@ -121,7 +122,7 @@ public class MeasuredParagraph {
private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);
// The native MeasuredParagraph.
- private @Nullable NativeMeasuredParagraph mNativeMeasuredParagraph;
+ private @Nullable MeasuredText mMeasuredText;
// Following two objects are for avoiding object allocation.
private @NonNull TextPaint mCachedPaint = new TextPaint();
@@ -149,7 +150,7 @@ public class MeasuredParagraph {
mWidths.clear();
mFontMetrics.clear();
mSpanEndCache.clear();
- mNativeMeasuredParagraph = null;
+ mMeasuredText = null;
}
/**
@@ -245,8 +246,8 @@ public class MeasuredParagraph {
* This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
* Returns null in other cases.
*/
- public NativeMeasuredParagraph getNativeMeasuredParagraph() {
- return mNativeMeasuredParagraph;
+ public MeasuredText getMeasuredText() {
+ return mMeasuredText;
}
/**
@@ -259,7 +260,7 @@ public class MeasuredParagraph {
* @param end the exclusive end offset of the target region in the text
*/
public float getWidth(int start, int end) {
- if (mNativeMeasuredParagraph == null) {
+ if (mMeasuredText == null) {
// We have result in Java.
final float[] widths = mWidths.getRawArray();
float r = 0.0f;
@@ -269,7 +270,7 @@ public class MeasuredParagraph {
return r;
} else {
// We have result in native.
- return mNativeMeasuredParagraph.getWidth(start, end);
+ return mMeasuredText.getWidth(start, end);
}
}
@@ -281,7 +282,7 @@ public class MeasuredParagraph {
*/
public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@NonNull Rect bounds) {
- mNativeMeasuredParagraph.getBounds(mCopiedBuffer, start, end, bounds);
+ mMeasuredText.getBounds(start, end, bounds);
}
/**
@@ -290,7 +291,7 @@ public class MeasuredParagraph {
* This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
*/
public float getCharWidthAt(@IntRange(from = 0) int offset) {
- return mNativeMeasuredParagraph.getCharWidthAt(offset);
+ return mMeasuredText.getCharWidthAt(offset);
}
/**
@@ -391,12 +392,13 @@ public class MeasuredParagraph {
@Nullable MeasuredParagraph recycle) {
final MeasuredParagraph mt = recycle == null ? obtain() : recycle;
mt.resetAndAnalyzeBidi(text, start, end, textDir);
- final NativeMeasuredParagraph.Builder builder = new NativeMeasuredParagraph.Builder();
+ final MeasuredText.Builder builder = new MeasuredText.Builder(mt.mCopiedBuffer);
+ builder.setComputeHyphenation(computeHyphenation);
+ builder.setComputeLayout(computeLayout);
if (mt.mTextLength == 0) {
// Need to build empty native measured text for StaticLayout.
// TODO: Stop creating empty measured text for empty lines.
- mt.mNativeMeasuredParagraph = builder.build(mt.mCopiedBuffer, computeHyphenation,
- computeLayout);
+ mt.mMeasuredText = builder.build();
} else {
if (mt.mSpanned == null) {
// No style change by MetricsAffectingSpan. Just measure all text.
@@ -417,8 +419,7 @@ public class MeasuredParagraph {
mt.mSpanEndCache.append(spanEnd);
}
}
- mt.mNativeMeasuredParagraph = builder.build(mt.mCopiedBuffer, computeHyphenation,
- computeLayout);
+ mt.mMeasuredText = builder.build();
}
return mt;
@@ -490,7 +491,7 @@ public class MeasuredParagraph {
private void applyReplacementRun(@NonNull ReplacementSpan replacement,
@IntRange(from = 0) int start, // inclusive, in copied buffer
@IntRange(from = 0) int end, // exclusive, in copied buffer
- @Nullable NativeMeasuredParagraph.Builder builder) {
+ @Nullable MeasuredText.Builder builder) {
// Use original text. Shouldn't matter.
// TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
// backward compatibility? or Should we initialize them for getFontMetricsInt?
@@ -510,7 +511,7 @@ public class MeasuredParagraph {
private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer
@IntRange(from = 0) int end, // exclusive, in copied buffer
- @Nullable NativeMeasuredParagraph.Builder builder) {
+ @Nullable MeasuredText.Builder builder) {
if (mLtrWithoutBidi) {
// If the whole text is LTR direction, just apply whole region.
@@ -552,7 +553,7 @@ public class MeasuredParagraph {
@Nullable MetricAffectingSpan[] spans,
@IntRange(from = 0) int start, // inclusive, in original text buffer
@IntRange(from = 0) int end, // exclusive, in original text buffer
- @Nullable NativeMeasuredParagraph.Builder builder) {
+ @Nullable MeasuredText.Builder builder) {
mCachedPaint.set(paint);
// XXX paint should not have a baseline shift, but...
mCachedPaint.baselineShift = 0;
@@ -658,6 +659,6 @@ public class MeasuredParagraph {
* This only works if the MeasuredParagraph is computed with buildForStaticLayout.
*/
public @IntRange(from = 0) int getMemoryUsage() {
- return mNativeMeasuredParagraph.getMemoryUsage();
+ return mMeasuredText.getMemoryUsage();
}
}
diff --git a/core/java/android/text/NativeMeasuredParagraph.java b/core/java/android/text/NativeMeasuredParagraph.java
deleted file mode 100644
index bfdccca2955b..000000000000
--- a/core/java/android/text/NativeMeasuredParagraph.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import android.annotation.FloatRange;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.graphics.Paint;
-import android.graphics.Rect;
-
-import dalvik.annotation.optimization.CriticalNative;
-
-import libcore.util.NativeAllocationRegistry;
-
-/**
- * A native implementation of measured paragraph.
- * TODO: Consider to make this class public.
- * @hide
- */
-public class NativeMeasuredParagraph {
- private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
- NativeMeasuredParagraph.class.getClassLoader(), nGetReleaseFunc(), 1024);
-
- private long mNativePtr;
- private @NonNull char[] mChars;
-
- // Use builder instead.
- private NativeMeasuredParagraph(long ptr, @NonNull char[] chars) {
- mNativePtr = ptr;
- mChars = chars;
- }
-
- /**
- * Returns a characters of this paragraph.
- */
- public char[] getChars() {
- return mChars;
- }
-
- /**
- * Returns a width of the given region
- */
- public float getWidth(int start, int end) {
- return nGetWidth(mNativePtr, start, end);
- }
-
- /**
- * Returns a memory usage of the native object.
- */
- public int getMemoryUsage() {
- return nGetMemoryUsage(mNativePtr);
- }
-
- /**
- * Fills the boundary box of the given region
- */
- public void getBounds(char[] buf, int start, int end, Rect rect) {
- nGetBounds(mNativePtr, buf, start, end, rect);
- }
-
- /**
- * Returns the width of the character at the given offset
- */
- public float getCharWidthAt(int offset) {
- return nGetCharWidthAt(mNativePtr, offset);
- }
-
- /**
- * Returns a native pointer of the underlying native object.
- */
- public long getNativePtr() {
- return mNativePtr;
- }
-
- @CriticalNative
- private static native float nGetWidth(/* Non Zero */ long nativePtr,
- @IntRange(from = 0) int start,
- @IntRange(from = 0) int end);
-
- @CriticalNative
- private static native /* Non Zero */ long nGetReleaseFunc();
-
- @CriticalNative
- private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr);
-
- private static native void nGetBounds(long nativePtr, char[] buf, int start, int end,
- Rect rect);
-
- @CriticalNative
- private static native float nGetCharWidthAt(long nativePtr, int offset);
-
- /**
- * A builder for the NativeMeasuredParagraph
- */
- public static class Builder {
- private final long mNativePtr;
-
- public Builder() {
- mNativePtr = nInitBuilder();
- }
-
- /**
- * Apply styles to given range
- */
- public void addStyleRun(@NonNull Paint paint, int start, int end, boolean isRtl) {
- nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl);
- }
-
- /**
- * Tells native that the given range is replaced with the object of given width.
- */
- public void addReplacementRun(@NonNull Paint paint, int start, int end, float width) {
- nAddReplacementRun(mNativePtr, paint.getNativeInstance(), start, end, width);
- }
-
- /**
- * Build the NativeMeasuredParagraph
- */
- public NativeMeasuredParagraph build(char[] text, boolean computeHyphenation,
- boolean computeLayout) {
- try {
- long ptr = nBuildNativeMeasuredParagraph(mNativePtr, text, computeHyphenation,
- computeLayout);
- NativeMeasuredParagraph res = new NativeMeasuredParagraph(ptr, text);
- sRegistry.registerNativeAllocation(res, ptr);
- return res;
- } finally {
- nFreeBuilder(mNativePtr);
- }
- }
-
- private static native /* Non Zero */ long nInitBuilder();
-
- /**
- * Apply style to make native measured text.
- *
- * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
- * @param paintPtr The native paint pointer to be applied.
- * @param start The start offset in the copied buffer.
- * @param end The end offset in the copied buffer.
- * @param isRtl True if the text is RTL.
- */
- private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
- /* Non Zero */ long paintPtr,
- @IntRange(from = 0) int start,
- @IntRange(from = 0) int end,
- boolean isRtl);
- /**
- * Apply ReplacementRun to make native measured text.
- *
- * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
- * @param paintPtr The native paint pointer to be applied.
- * @param start The start offset in the copied buffer.
- * @param end The end offset in the copied buffer.
- * @param width The width of the replacement.
- */
- private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
- /* Non Zero */ long paintPtr,
- @IntRange(from = 0) int start,
- @IntRange(from = 0) int end,
- @FloatRange(from = 0) float width);
-
- private static native long nBuildNativeMeasuredParagraph(
- /* Non Zero */ long nativeBuilderPtr,
- @NonNull char[] text,
- boolean computeHyphenation,
- boolean computeLayout);
-
- private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
- }
-}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index d2f085369448..2cf0262a1d28 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Paint;
+import android.graphics.text.LineBreaker;
import android.os.Build;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
@@ -55,7 +56,7 @@ public class StaticLayout extends Layout {
*
* - Create MeasuredParagraph by MeasuredParagraph.buildForStaticLayout which measures in
* native.
- * - Run NativeLineBreaker.computeLineBreaks() to obtain line breaks for the paragraph.
+ * - Run LineBreaker.computeLineBreaks() to obtain line breaks for the paragraph.
*
* After all paragraphs, call finish() to release expensive buffers.
*/
@@ -634,7 +635,7 @@ public class StaticLayout extends Layout {
indents = null;
}
- final NativeLineBreaker lineBreaker = new NativeLineBreaker.Builder()
+ final LineBreaker lineBreaker = new LineBreaker.Builder()
.setBreakStrategy(b.mBreakStrategy)
.setHyphenationFrequency(b.mHyphenationFrequency)
// TODO: Support more justification mode, e.g. letter spacing, stretching.
@@ -642,8 +643,8 @@ public class StaticLayout extends Layout {
.setIndents(indents)
.build();
- NativeLineBreaker.ParagraphConstraints constraints =
- new NativeLineBreaker.ParagraphConstraints();
+ LineBreaker.ParagraphConstraints constraints =
+ new LineBreaker.ParagraphConstraints();
PrecomputedText.ParagraphInfo[] paragraphInfo = null;
final Spanned spanned = (source instanceof Spanned) ? (Spanned) source : null;
@@ -739,8 +740,8 @@ public class StaticLayout extends Layout {
constraints.setIndent(firstWidth, firstWidthLineCount);
constraints.setTabStops(variableTabStops, TAB_INCREMENT);
- NativeLineBreaker.Result res = lineBreaker.computeLineBreaks(
- measuredPara.getNativeMeasuredParagraph(), constraints, mLineCount);
+ LineBreaker.Result res = lineBreaker.computeLineBreaks(
+ measuredPara.getMeasuredText(), constraints, mLineCount);
int breakCount = res.getLineCount();
if (lineBreakCapacity < breakCount) {
lineBreakCapacity = breakCount;
@@ -776,7 +777,7 @@ public class StaticLayout extends Layout {
width += lineWidths[i];
} else {
for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
- width += measuredPara.getCharWidthAt(j - paraStart);
+ width += measuredPara.getCharWidthAt(j);
}
}
hasTab |= hasTabs[i];
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index e31e928bb917..195de07d8595 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,7 +16,10 @@
package android.text;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,6 +45,7 @@ import android.text.style.CharacterStyle;
import android.text.style.EasyEditSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
+import android.text.style.LineBackgroundSpan;
import android.text.style.LocaleSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
@@ -69,7 +73,9 @@ import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
import java.lang.reflect.Array;
+import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -87,6 +93,44 @@ public class TextUtils {
private static final String ELLIPSIS_NORMAL = "\u2026"; // HORIZONTAL ELLIPSIS (…)
private static final String ELLIPSIS_TWO_DOTS = "\u2025"; // TWO DOT LEADER (‥)
+ private static final int LINE_FEED_CODE_POINT = 10;
+ private static final int NBSP_CODE_POINT = 160;
+
+ /**
+ * Flags for {@link #makeSafeForPresentation(String, int, float, int)}
+ *
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef(flag = true, prefix = "CLEAN_STRING_FLAG_",
+ value = {SAFE_STRING_FLAG_TRIM, SAFE_STRING_FLAG_SINGLE_LINE,
+ SAFE_STRING_FLAG_FIRST_LINE})
+ public @interface SafeStringFlags {}
+
+ /**
+ * Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges
+ * of the label.
+ *
+ * @see #makeSafeForPresentation(String, int, float, int)
+ */
+ public static final int SAFE_STRING_FLAG_TRIM = 0x1;
+
+ /**
+ * Force entire string into single line of text (no newlines). Cannot be set at the same time as
+ * {@link #SAFE_STRING_FLAG_FIRST_LINE}.
+ *
+ * @see #makeSafeForPresentation(String, int, float, int)
+ */
+ public static final int SAFE_STRING_FLAG_SINGLE_LINE = 0x2;
+
+ /**
+ * Return only first line of text (truncate at first newline). Cannot be set at the same time as
+ * {@link #SAFE_STRING_FLAG_SINGLE_LINE}.
+ *
+ * @see #makeSafeForPresentation(String, int, float, int)
+ */
+ public static final int SAFE_STRING_FLAG_FIRST_LINE = 0x4;
+
/** {@hide} */
@NonNull
public static String getEllipsisString(@NonNull TextUtils.TruncateAt method) {
@@ -687,7 +731,9 @@ public class TextUtils {
/** @hide */
public static final int ACCESSIBILITY_URL_SPAN = 26;
/** @hide */
- public static final int LAST_SPAN = ACCESSIBILITY_URL_SPAN;
+ public static final int LINE_BACKGROUND_SPAN = 27;
+ /** @hide */
+ public static final int LAST_SPAN = LINE_BACKGROUND_SPAN;
/**
* Flatten a CharSequence and whatever styles can be copied across processes
@@ -878,6 +924,10 @@ public class TextUtils {
readSpan(p, sp, new AccessibilityURLSpan(p));
break;
+ case LINE_BACKGROUND_SPAN:
+ readSpan(p, sp, new LineBackgroundSpan.Standard(p));
+ break;
+
default:
throw new RuntimeException("bogus span encoding " + kind);
}
@@ -2116,6 +2166,222 @@ public class TextUtils {
return trimmed;
}
+ private static boolean isNewline(int codePoint) {
+ int type = Character.getType(codePoint);
+ return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
+ || codePoint == LINE_FEED_CODE_POINT;
+ }
+
+ private static boolean isWhiteSpace(int codePoint) {
+ return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
+ }
+
+ /**
+ * Remove html, remove bad characters, and truncate string.
+ *
+ * <p>This method is meant to remove common mistakes and nefarious formatting from strings that
+ * were loaded from untrusted sources (such as other packages).
+ *
+ * <p>This method first {@link Html#fromHtml treats the string like HTML} and then ...
+ * <ul>
+ * <li>Removes new lines or truncates at first new line
+ * <li>Trims the white-space off the end
+ * <li>Truncates the string
+ * </ul>
+ * ... if specified.
+ *
+ * @param unclean The input string
+ * @param maxCharactersToConsider The maximum number of characters of {@code unclean} to
+ * consider from the input string. {@code 0} disables this
+ * feature.
+ * @param ellipsizeDip Assuming maximum length of the string (in dip), assuming font size 42.
+ * This is roughly 50 characters for {@code ellipsizeDip == 1000}.<br />
+ * Usually ellipsizing should be left to the view showing the string. If a
+ * string is used as an input to another string, it might be useful to
+ * control the length of the input string though. {@code 0} disables this
+ * feature.
+ * @param flags Flags controlling cleaning behavior (Can be {@link #SAFE_STRING_FLAG_TRIM},
+ * {@link #SAFE_STRING_FLAG_SINGLE_LINE},
+ * and {@link #SAFE_STRING_FLAG_FIRST_LINE})
+ *
+ * @return The cleaned string
+ */
+ public static @NonNull CharSequence makeSafeForPresentation(@NonNull String unclean,
+ @IntRange(from = 0) int maxCharactersToConsider,
+ @FloatRange(from = 0) float ellipsizeDip, @SafeStringFlags int flags) {
+ boolean onlyKeepFirstLine = ((flags & SAFE_STRING_FLAG_FIRST_LINE) != 0);
+ boolean forceSingleLine = ((flags & SAFE_STRING_FLAG_SINGLE_LINE) != 0);
+ boolean trim = ((flags & SAFE_STRING_FLAG_TRIM) != 0);
+
+ Preconditions.checkNotNull(unclean);
+ Preconditions.checkArgumentNonnegative(maxCharactersToConsider);
+ Preconditions.checkArgumentNonNegative(ellipsizeDip, "ellipsizeDip");
+ Preconditions.checkFlagsArgument(flags, SAFE_STRING_FLAG_TRIM
+ | SAFE_STRING_FLAG_SINGLE_LINE | SAFE_STRING_FLAG_FIRST_LINE);
+ Preconditions.checkArgument(!(onlyKeepFirstLine && forceSingleLine),
+ "Cannot set SAFE_STRING_FLAG_SINGLE_LINE and SAFE_STRING_FLAG_FIRST_LINE at the"
+ + "same time");
+
+ String shortString;
+ if (maxCharactersToConsider > 0) {
+ shortString = unclean.substring(0, Math.min(unclean.length(), maxCharactersToConsider));
+ } else {
+ shortString = unclean;
+ }
+
+ // Treat string as HTML. This
+ // - converts HTML symbols: e.g. &szlig; -> ß
+ // - applies some HTML tags: e.g. <br> -> \n
+ // - removes invalid characters such as \b
+ // - removes html styling, such as <b>
+ // - applies html formatting: e.g. a<p>b</p>c -> a\n\nb\n\nc
+ // - replaces some html tags by "object replacement" markers: <img> -> \ufffc
+ // - Removes leading white space
+ // - Removes all trailing white space beside a single space
+ // - Collapses double white space
+ StringWithRemovedChars gettingCleaned = new StringWithRemovedChars(
+ Html.fromHtml(shortString).toString());
+
+ int firstNonWhiteSpace = -1;
+ int firstTrailingWhiteSpace = -1;
+
+ // Remove new lines (if requested) and control characters.
+ int uncleanLength = gettingCleaned.length();
+ for (int offset = 0; offset < uncleanLength; ) {
+ int codePoint = gettingCleaned.codePointAt(offset);
+ int type = Character.getType(codePoint);
+ int codePointLen = Character.charCount(codePoint);
+ boolean isNewline = isNewline(codePoint);
+
+ if (onlyKeepFirstLine && isNewline) {
+ gettingCleaned.removeAllCharAfter(offset);
+ break;
+ } else if (forceSingleLine && isNewline) {
+ gettingCleaned.removeRange(offset, offset + codePointLen);
+ } else if (type == Character.CONTROL && !isNewline) {
+ gettingCleaned.removeRange(offset, offset + codePointLen);
+ } else if (trim && !isWhiteSpace(codePoint)) {
+ // This is only executed if the code point is not removed
+ if (firstNonWhiteSpace == -1) {
+ firstNonWhiteSpace = offset;
+ }
+ firstTrailingWhiteSpace = offset + codePointLen;
+ }
+
+ offset += codePointLen;
+ }
+
+ if (trim) {
+ // Remove leading and trailing white space
+ if (firstNonWhiteSpace == -1) {
+ // No non whitespace found, remove all
+ gettingCleaned.removeAllCharAfter(0);
+ } else {
+ if (firstNonWhiteSpace > 0) {
+ gettingCleaned.removeAllCharBefore(firstNonWhiteSpace);
+ }
+ if (firstTrailingWhiteSpace < uncleanLength) {
+ gettingCleaned.removeAllCharAfter(firstTrailingWhiteSpace);
+ }
+ }
+ }
+
+ if (ellipsizeDip == 0) {
+ return gettingCleaned.toString();
+ } else {
+ // Truncate
+ final TextPaint paint = new TextPaint();
+ paint.setTextSize(42);
+
+ return TextUtils.ellipsize(gettingCleaned.toString(), paint, ellipsizeDip,
+ TextUtils.TruncateAt.END);
+ }
+ }
+
+ /**
+ * A special string manipulation class. Just records removals and executes the when onString()
+ * is called.
+ */
+ private static class StringWithRemovedChars {
+ /** The original string */
+ private final String mOriginal;
+
+ /**
+ * One bit per char in string. If bit is set, character needs to be removed. If whole
+ * bit field is not initialized nothing needs to be removed.
+ */
+ private BitSet mRemovedChars;
+
+ StringWithRemovedChars(@NonNull String original) {
+ mOriginal = original;
+ }
+
+ /**
+ * Mark all chars in a range {@code [firstRemoved - firstNonRemoved[} (not including
+ * firstNonRemoved) as removed.
+ */
+ void removeRange(int firstRemoved, int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters before {@code firstNonRemoved}.
+ */
+ void removeAllCharBefore(int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(0, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters after and including {@code firstRemoved}.
+ */
+ void removeAllCharAfter(int firstRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, mOriginal.length());
+ }
+
+ @Override
+ public String toString() {
+ // Common case, no chars removed
+ if (mRemovedChars == null) {
+ return mOriginal;
+ }
+
+ StringBuilder sb = new StringBuilder(mOriginal.length());
+ for (int i = 0; i < mOriginal.length(); i++) {
+ if (!mRemovedChars.get(i)) {
+ sb.append(mOriginal.charAt(i));
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return length or the original string
+ */
+ int length() {
+ return mOriginal.length();
+ }
+
+ /**
+ * Return codePoint of original string at a certain {@code offset}
+ */
+ int codePointAt(int offset) {
+ return mOriginal.codePointAt(offset);
+ }
+ }
+
private static Object sLock = new Object();
private static char[] sTemp = null;
diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java
index 9c7859fb11e4..5a55fd749150 100644
--- a/core/java/android/text/style/LineBackgroundSpan.java
+++ b/core/java/android/text/style/LineBackgroundSpan.java
@@ -16,15 +16,110 @@
package android.text.style;
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Px;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
-public interface LineBackgroundSpan
-extends ParagraphStyle
+/**
+ * Used to change the background of lines where the span is attached to.
+ */
+public interface LineBackgroundSpan extends ParagraphStyle
{
- public void drawBackground(Canvas c, Paint p,
- int left, int right,
- int top, int baseline, int bottom,
- CharSequence text, int start, int end,
- int lnum);
+ /**
+ * Draw the background on the canvas.
+ *
+ * @param canvas canvas on which the span should be rendered
+ * @param paint paint used to draw text, which should be left unchanged on exit
+ * @param left left position of the line relative to input canvas, in pixels
+ * @param right right position of the line relative to input canvas, in pixels
+ * @param top top position of the line relative to input canvas, in pixels
+ * @param baseline baseline of the text relative to input canvas, in pixels
+ * @param bottom bottom position of the line relative to input canvas, in pixels
+ * @param text current text
+ * @param start start character index of the line
+ * @param end end character index of the line
+ * @param lineNumber line number in the current text layout
+ */
+ void drawBackground(@NonNull Canvas canvas, @NonNull Paint paint,
+ @Px int left, @Px int right,
+ @Px int top, @Px int baseline, @Px int bottom,
+ @NonNull CharSequence text, int start, int end,
+ int lineNumber);
+ /**
+ * Default implementation of the {@link LineBackgroundSpan}, which changes the background
+ * color of the lines to which the span is attached.
+ */
+ class Standard implements LineBackgroundSpan, ParcelableSpan {
+
+ private final int mColor;
+
+ /**
+ * Constructor taking a color integer.
+ *
+ * @param color Color integer that defines the background color.
+ */
+ public Standard(@ColorInt int color) {
+ mColor = color;
+ }
+
+ /**
+ * Creates a {@link LineBackgroundSpan.Standard} from a parcel
+ */
+ public Standard(@NonNull Parcel src) {
+ mColor = src.readInt();
+ }
+
+ @Override
+ public int getSpanTypeId() {
+ return getSpanTypeIdInternal();
+ }
+
+ /** @hide */
+ @Override
+ public int getSpanTypeIdInternal() {
+ return TextUtils.LINE_BACKGROUND_SPAN;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ writeToParcelInternal(dest, flags);
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+
+ /**
+ * @return the color of this span.
+ * @see Standard#Standard(int)
+ */
+ @ColorInt
+ public final int getColor() {
+ return mColor;
+ }
+
+ @Override
+ public void drawBackground(@NonNull Canvas canvas, @NonNull Paint paint,
+ @Px int left, @Px int right,
+ @Px int top, @Px int baseline, @Px int bottom,
+ @NonNull CharSequence text, int start, int end,
+ int lineNumber) {
+ final int originColor = paint.getColor();
+ paint.setColor(mColor);
+ canvas.drawRect(left, right, top, bottom, paint);
+ paint.setColor(originColor);
+ }
+ }
}
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index 2dc4f6001a06..648bd1bba20c 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -29,8 +29,33 @@ import android.text.TextPaint;
import android.text.TextUtils;
/**
- * Sets the text color, size, style, and typeface to match a TextAppearance
- * resource.
+ * Sets the text appearance using the given
+ * {@link android.R.styleable#TextAppearance TextAppearance} attributes.
+ * By default {@link TextAppearanceSpan} only changes the specified attributes in XML.
+ * {@link android.R.styleable#TextAppearance_textColorHighlight textColorHighlight},
+ * {@link android.R.styleable#TextAppearance_textColorHint textColorHint},
+ * {@link android.R.styleable#TextAppearance_textAllCaps textAllCaps} and
+ * {@link android.R.styleable#TextAppearance_fallbackLineSpacing fallbackLineSpacing}
+ * are not supported by {@link TextAppearanceSpan}.
+ *
+ * {@see android.widget.TextView#setTextAppearance(int)}
+ *
+ * @attr ref android.R.styleable#TextAppearance_fontFamily
+ * @attr ref android.R.styleable#TextAppearance_textColor
+ * @attr ref android.R.styleable#TextAppearance_textColorLink
+ * @attr ref android.R.styleable#TextAppearance_textFontWeight
+ * @attr ref android.R.styleable#TextAppearance_textSize
+ * @attr ref android.R.styleable#TextAppearance_textStyle
+ * @attr ref android.R.styleable#TextAppearance_typeface
+ * @attr ref android.R.styleable#TextAppearance_shadowColor
+ * @attr ref android.R.styleable#TextAppearance_shadowDx
+ * @attr ref android.R.styleable#TextAppearance_shadowDy
+ * @attr ref android.R.styleable#TextAppearance_shadowRadius
+ * @attr ref android.R.styleable#TextAppearance_elegantTextHeight
+ * @attr ref android.R.styleable#TextAppearance_letterSpacing
+ * @attr ref android.R.styleable#TextAppearance_fontFeatureSettings
+ * @attr ref android.R.styleable#TextAppearance_fontVariationSettings
+ *
*/
public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
private final String mFamilyName;
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 319f080bbe63..bd2bef4f11ae 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -25,6 +25,7 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroupOverlay;
import com.android.internal.R;
@@ -413,7 +414,6 @@ public abstract class Visibility extends Transition {
}
}
final int finalVisibility = endVisibility;
- final ViewGroup finalSceneRoot = sceneRoot;
if (overlayView != null) {
// TODO: Need to do this for general case of adding to overlay
@@ -424,16 +424,32 @@ public abstract class Visibility extends Transition {
sceneRoot.getLocationOnScreen(loc);
overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
- sceneRoot.getOverlay().add(overlayView);
+ final ViewGroupOverlay overlay = sceneRoot.getOverlay();
+ overlay.add(overlayView);
Animator animator = onDisappear(sceneRoot, overlayView, startValues, endValues);
if (animator == null) {
- sceneRoot.getOverlay().remove(overlayView);
+ overlay.remove(overlayView);
} else {
final View finalOverlayView = overlayView;
addListener(new TransitionListenerAdapter() {
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ overlay.remove(finalOverlayView);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ if (finalOverlayView.getParent() == null) {
+ overlay.add(finalOverlayView);
+ } else {
+ cancel();
+ }
+ }
+
@Override
public void onTransitionEnd(Transition transition) {
- finalSceneRoot.getOverlay().remove(finalOverlayView);
+ overlay.remove(finalOverlayView);
transition.removeListener(this);
}
});
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index 209451bcfe6a..cd2b6ce3dc67 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -737,8 +737,7 @@ public final class ProtoInputStream extends ProtoStream {
fillBuffer();
if (mOffset + n <= mEnd) {
// fast path read. String is well within the current buffer
- String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
- StandardCharsets.UTF_8);
+ String value = new String(mBuffer, mOffset, n, StandardCharsets.UTF_8);
incOffset(n);
return value;
} else if (n <= mBufferSize) {
@@ -752,14 +751,13 @@ public final class ProtoInputStream extends ProtoStream {
mDiscardedBytes += mOffset;
mOffset = 0;
- String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
- StandardCharsets.UTF_8);
+ String value = new String(mBuffer, mOffset, n, StandardCharsets.UTF_8);
incOffset(n);
return value;
}
// Otherwise, the string is too large to use the buffer. Create the string from a
// separate byte array.
- return StringFactory.newStringFromBytes(readRawBytes(n), 0, n, StandardCharsets.UTF_8);
+ return new String(readRawBytes(n), 0, n, StandardCharsets.UTF_8);
}
/**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index f428c798d7f5..e9f1edf52b5f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -245,9 +245,8 @@ public final class DisplayCutout {
* passed, it's treated as an empty rectangle (0,0)-(0,0).
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
- public DisplayCutout(
- Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop,
- @Nullable Rect boundRight, @Nullable Rect boundBottom) {
+ public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
+ @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
this(safeInsets.toRect(), boundLeft, boundTop, boundRight, boundBottom, true);
}
@@ -262,7 +261,7 @@ public final class DisplayCutout {
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
- public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) {
+ public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
this(safeInsets, extractBoundsFromList(safeInsets, boundingRects),
true /* copyArguments */);
}
@@ -313,18 +312,20 @@ public final class DisplayCutout {
for (int i = 0; i < sortedBounds.length; ++i) {
sortedBounds[i] = ZERO_RECT;
}
- for (Rect bound : boundingRects) {
- // There will be at most one non-functional area per short edge of the device, and none
- // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
- // TODO(b/117199965): Refine the logic to handle edge cases.
- if (bound.left == 0) {
- sortedBounds[BOUNDS_POSITION_LEFT] = bound;
- } else if (bound.top == 0) {
- sortedBounds[BOUNDS_POSITION_TOP] = bound;
- } else if (safeInsets.right > 0) {
- sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
- } else if (safeInsets.bottom > 0) {
- sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ if (safeInsets != null && boundingRects != null) {
+ for (Rect bound : boundingRects) {
+ // There is at most one non-functional area per short edge of the device, but none
+ // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
+ // TODO(b/117199965): Refine the logic to handle edge cases.
+ if (bound.left == 0) {
+ sortedBounds[BOUNDS_POSITION_LEFT] = bound;
+ } else if (bound.top == 0) {
+ sortedBounds[BOUNDS_POSITION_TOP] = bound;
+ } else if (safeInsets.right > 0) {
+ sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
+ } else if (safeInsets.bottom > 0) {
+ sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ }
}
}
return sortedBounds;
@@ -389,6 +390,7 @@ public final class DisplayCutout {
* @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
* returned.
*/
+ @NonNull
public List<Rect> getBoundingRects() {
List<Rect> result = new ArrayList<>();
for (Rect bound : getBoundingRectsAll()) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7271a9e4616f..0d33bbd1fc76 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -97,6 +97,8 @@ public class SurfaceControl implements Parcelable {
private static native void nativeSetMatrix(long transactionObj, long nativeObject,
float dsdx, float dtdx,
float dtdy, float dsdy);
+ private static native void nativeSetColorTransform(long transactionObj, long nativeObject,
+ float[] matrix, float[] translation);
private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
private static native void nativeSetFlags(long transactionObj, long nativeObject,
int flags, int mask);
@@ -945,6 +947,18 @@ public class SurfaceControl implements Parcelable {
}
}
+ /**
+ * Sets the color transform for the Surface.
+ * @param matrix A float array with 9 values represents a 3x3 transform matrix
+ * @param translation A float array with 3 values represents a translation vector
+ */
+ public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
+ checkNotReleased();
+ synchronized (SurfaceControl.class) {
+ sGlobalTransaction.setColorTransform(this, matrix, translation);
+ }
+ }
+
public void setWindowCrop(Rect crop) {
checkNotReleased();
synchronized (SurfaceControl.class) {
@@ -1438,6 +1452,18 @@ public class SurfaceControl implements Parcelable {
return this;
}
+ /**
+ * Sets the color transform for the Surface.
+ * @param matrix A float array with 9 values represents a 3x3 transform matrix
+ * @param translation A float array with 3 values represents a translation vector
+ */
+ public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
+ @Size(3) float[] translation) {
+ sc.checkNotReleased();
+ nativeSetColorTransform(mNativeObject, sc.mNativeObject, matrix, translation);
+ return this;
+ }
+
@UnsupportedAppUsage
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
sc.checkNotReleased();
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index b361ab456b2a..06b73dd29b3d 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -16,8 +16,12 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.ArrayMap;
+import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo;
/**
* Helper class to handle situations where you want a view to have a larger touch area than its
@@ -78,6 +82,11 @@ public class TouchDelegate {
private int mSlop;
/**
+ * Touch delegate information for accessibility
+ */
+ private TouchDelegateInfo mTouchDelegateInfo;
+
+ /**
* Constructor
*
* @param bounds Bounds in local coordinates of the containing view that should be mapped to
@@ -145,4 +154,20 @@ public class TouchDelegate {
}
return handled;
}
+
+ /**
+ * Return a {@link TouchDelegateInfo} mapping from regions (in view coordinates) to
+ * delegated views for accessibility usage.
+ *
+ * @return A TouchDelegateInfo.
+ */
+ @NonNull
+ public TouchDelegateInfo getTouchDelegateInfo() {
+ if (mTouchDelegateInfo == null) {
+ final ArrayMap<Region, View> targetMap = new ArrayMap<>(1);
+ targetMap.put(new Region(mBounds), mDelegateView);
+ mTouchDelegateInfo = new TouchDelegateInfo(targetMap);
+ }
+ return mTouchDelegateInfo;
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cddd83c45c75..cc58b8928f6e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7315,17 +7315,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Here we check whether we still need the default focus highlight, and switch it on/off.
switchDefaultFocusHighlight();
- InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (!gainFocus) {
if (isPressed()) {
setPressed(false);
}
- if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
- imm.focusOut(this);
+ if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
+ notifyFocusChangeToInputMethodManager(false /* hasFocus */);
}
onFocusLost();
- } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
- imm.focusIn(this);
+ } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
+ notifyFocusChangeToInputMethodManager(true /* hasFocus */);
}
invalidate(true);
@@ -7341,6 +7340,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
}
+ /**
+ * Notify {@link InputMethodManager} about the focus change of the {@link View}.
+ *
+ * <p>Does nothing when {@link InputMethodManager} is not available.</p>
+ *
+ * @param hasFocus {@code true} when the {@link View} is being focused.
+ */
+ private void notifyFocusChangeToInputMethodManager(boolean hasFocus) {
+ final InputMethodManager imm =
+ getContext().getSystemService(InputMethodManager.class);
+ if (imm == null) {
+ return;
+ }
+ if (hasFocus) {
+ imm.focusIn(this);
+ } else {
+ imm.focusOut(this);
+ }
+ }
+
/** @hide */
public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) {
if (canNotifyAutofillEnterExitEvent()) {
@@ -8881,6 +8900,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
populateAccessibilityNodeInfoDrawingOrderInParent(info);
info.setPaneTitle(mAccessibilityPaneTitle);
info.setHeading(isAccessibilityHeading());
+
+ if (mTouchDelegate != null) {
+ info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
+ }
}
/**
@@ -12481,7 +12504,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
onFinishTemporaryDetach();
if (hasWindowFocus() && hasFocus()) {
- getContext().getSystemService(InputMethodManager.class).focusIn(this);
+ notifyFocusChangeToInputMethodManager(true /* hasFocus */);
}
notifyEnterOrExitForAutoFillIfNeeded(true);
}
@@ -12872,20 +12895,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* focus, false otherwise.
*/
public void onWindowFocusChanged(boolean hasWindowFocus) {
- InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
if (!hasWindowFocus) {
if (isPressed()) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
- if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
- imm.focusOut(this);
+ if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+ notifyFocusChangeToInputMethodManager(false /* hasFocus */);
}
removeLongPressCallback();
removeTapCallback();
onFocusLost();
- } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
- imm.focusIn(this);
+ } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+ notifyFocusChangeToInputMethodManager(true /* hasFocus */);
}
refreshDrawableState();
@@ -14255,9 +14277,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).onChildVisibilityChanged(this,
- (changed & VISIBILITY_MASK), newVisibility);
- ((View) mParent).invalidate(true);
+ ViewGroup parent = (ViewGroup) mParent;
+ parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+ newVisibility);
+ parent.invalidate(true);
} else if (mParent != null) {
mParent.invalidateChild(this, null);
}
@@ -17976,10 +17999,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
rebuildOutline();
if (isFocused()) {
- InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
- if (imm != null) {
- imm.focusIn(this);
- }
+ notifyFocusChangeToInputMethodManager(true /* hasFocus */);
}
}
@@ -24172,7 +24192,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* </ul>
* @return {@code true} if the method completes successfully, or
* {@code false} if it fails anywhere. Returning {@code false} means the system was unable to
- * do a drag, and so no drag operation is in progress.
+ * do a drag because of another ongoing operation or some other reasons.
*/
public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder,
Object myLocalState, int flags) {
@@ -24215,51 +24235,51 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y
+ " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y);
}
- if (mAttachInfo.mDragSurface != null) {
- mAttachInfo.mDragSurface.release();
- }
- mAttachInfo.mDragSurface = new Surface();
- mAttachInfo.mDragToken = null;
final ViewRootImpl root = mAttachInfo.mViewRootImpl;
final SurfaceSession session = new SurfaceSession(root.mSurface);
- final SurfaceControl surface = new SurfaceControl.Builder(session)
+ final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
.setName("drag surface")
.setSize(shadowSize.x, shadowSize.y)
.setFormat(PixelFormat.TRANSLUCENT)
.build();
+ final Surface surface = new Surface();
+ surface.copyFrom(surfaceControl);
+ IBinder token = null;
try {
- mAttachInfo.mDragSurface.copyFrom(surface);
- final Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
+ final Canvas canvas = surface.lockCanvas(null);
try {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
shadowBuilder.onDrawShadow(canvas);
} finally {
- mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas);
+ surface.unlockCanvasAndPost(canvas);
}
- // Cache the local state object for delivery with DragEvents
- root.setLocalDragState(myLocalState);
-
// repurpose 'shadowSize' for the last touch point
root.getLastTouchPoint(shadowSize);
- mAttachInfo.mDragToken = mAttachInfo.mSession.performDrag(
- mAttachInfo.mWindow, flags, surface, root.getLastTouchSource(),
+ token = mAttachInfo.mSession.performDrag(
+ mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(),
shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) {
- Log.d(VIEW_LOG_TAG, "performDrag returned " + mAttachInfo.mDragToken);
+ Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
}
-
- return mAttachInfo.mDragToken != null;
+ if (token != null) {
+ if (mAttachInfo.mDragSurface != null) {
+ mAttachInfo.mDragSurface.release();
+ }
+ mAttachInfo.mDragSurface = surface;
+ mAttachInfo.mDragToken = token;
+ // Cache the local state object for delivery with DragEvents
+ root.setLocalDragState(myLocalState);
+ }
+ return token != null;
} catch (Exception e) {
Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e);
return false;
} finally {
- if (mAttachInfo.mDragToken == null) {
- mAttachInfo.mDragSurface.destroy();
- mAttachInfo.mDragSurface = null;
- root.setLocalDragState(null);
+ if (token == null) {
+ surface.destroy();
}
session.kill();
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 982737aedc74..c1e94d8ff97e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1085,6 +1085,19 @@ public abstract class Window {
*
* <p>Refer to the individual flags for the permissions needed.
*
+ * @param flags The flag bits to add.
+ *
+ * @hide
+ */
+ public void addPrivateFlags(int flags) {
+ setPrivateFlags(flags, flags);
+ }
+
+ /**
+ * Add system flag bits.
+ *
+ * <p>Refer to the individual flags for the permissions needed.
+ *
* <p>Note: Only for updateable system components (aka. mainline modules)
*
* @param flags The flag bits to add.
@@ -1092,8 +1105,8 @@ public abstract class Window {
* @hide
*/
@SystemApi
- public void addPrivateFlags(int flags) {
- setPrivateFlags(flags, flags);
+ public void addSystemFlags(@WindowManager.LayoutParams.SystemFlags int flags) {
+ addPrivateFlags(flags);
}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 742df5e8a962..2d77cb4f3aca 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1670,7 +1670,7 @@ public interface WindowManager extends ViewManager {
*/
@SystemApi
@RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
- public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
+ public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
/**
* Indicates that this window is the rounded corners overlay present on some
@@ -1708,6 +1708,18 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION = 0x00800000;
/**
+ * An internal annotation for flags that can be specified to {@link #softInputMode}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "SYSTEM_FLAG_" }, value = {
+ SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ })
+ public @interface SystemFlags {}
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1781,8 +1793,8 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
name = "SUSTAINED_PERFORMANCE_MODE"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
- equals = PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ mask = SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ equals = SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
name = "HIDE_NON_SYSTEM_OVERLAY_WINDOWS"),
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4d3f0fc20ecd..e129091f5913 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -23,10 +23,12 @@ import static java.util.Collections.EMPTY_LIST;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -39,17 +41,21 @@ import android.text.style.AccessibilityClickableSpan;
import android.text.style.AccessibilityURLSpan;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
+import android.view.TouchDelegate;
import android.view.View;
import com.android.internal.R;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@@ -748,6 +754,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private CollectionInfo mCollectionInfo;
private CollectionItemInfo mCollectionItemInfo;
+ private TouchDelegateInfo mTouchDelegateInfo;
+
/**
* Hide constructor from clients.
*/
@@ -810,7 +818,7 @@ public class AccessibilityNodeInfo implements Parcelable {
public AccessibilityNodeInfo findFocus(int focus) {
enforceSealed();
enforceValidFocusType(focus);
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
@@ -834,7 +842,7 @@ public class AccessibilityNodeInfo implements Parcelable {
public AccessibilityNodeInfo focusSearch(int direction) {
enforceSealed();
enforceValidFocusDirection(direction);
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
@@ -866,7 +874,7 @@ public class AccessibilityNodeInfo implements Parcelable {
@UnsupportedAppUsage
public boolean refresh(Bundle arguments, boolean bypassCache) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -967,7 +975,7 @@ public class AccessibilityNodeInfo implements Parcelable {
if (mChildNodeIds == null) {
return null;
}
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
final long childId = mChildNodeIds.get(index);
@@ -1271,7 +1279,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getTraversalBefore() {
enforceSealed();
- return getNodeForAccessibilityId(mTraversalBefore);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalBefore);
}
/**
@@ -1332,7 +1340,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getTraversalAfter() {
enforceSealed();
- return getNodeForAccessibilityId(mTraversalAfter);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalAfter);
}
/**
@@ -1489,7 +1497,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public boolean performAction(int action) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1512,7 +1520,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public boolean performAction(int action, Bundle arguments) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1536,7 +1544,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1567,7 +1575,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1584,7 +1592,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityWindowInfo getWindow() {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1603,7 +1611,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
- return getNodeForAccessibilityId(mParentNodeId);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId);
}
/**
@@ -2783,7 +2791,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabelFor() {
enforceSealed();
- return getNodeForAccessibilityId(mLabelForId);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId);
}
/**
@@ -2835,7 +2843,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabeledBy() {
enforceSealed();
- return getNodeForAccessibilityId(mLabeledById);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById);
}
/**
@@ -2975,6 +2983,43 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Get the {@link TouchDelegateInfo} for touch delegate behavior with the represented view.
+ * It is possible for the same node to be pointed to by several regions. Use
+ * {@link TouchDelegateInfo#getRegionAt(int)} to get touch delegate target {@link Region}, and
+ * {@link TouchDelegateInfo#getTargetForRegion(Region)} for {@link AccessibilityNodeInfo} from
+ * the given region.
+ *
+ * @return {@link TouchDelegateInfo} or {@code null} if there are no touch delegates.
+ */
+ @Nullable
+ public TouchDelegateInfo getTouchDelegateInfo() {
+ if (mTouchDelegateInfo != null) {
+ mTouchDelegateInfo.setConnectionId(mConnectionId);
+ mTouchDelegateInfo.setWindowId(mWindowId);
+ }
+ return mTouchDelegateInfo;
+ }
+
+ /**
+ * Set touch delegate info if the represented view has a {@link TouchDelegate}.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an
+ * AccessibilityService.
+ * </p>
+ *
+ * @param delegatedInfo {@link TouchDelegateInfo} returned from
+ * {@link TouchDelegate#getTouchDelegateInfo()}.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setTouchDelegateInfo(@NonNull TouchDelegateInfo delegatedInfo) {
+ enforceNotSealed();
+ mTouchDelegateInfo = delegatedInfo;
+ }
+
+ /**
* Gets the value of a boolean property.
*
* @param property The property.
@@ -3340,6 +3385,10 @@ public class AccessibilityNodeInfo implements Parcelable {
if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
nonDefaultFields |= bitAt(fieldIndex);
}
+ fieldIndex++;
+ if (!Objects.equals(mTouchDelegateInfo, DEFAULT.mTouchDelegateInfo)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
int totalFields = fieldIndex;
parcel.writeLong(nonDefaultFields);
@@ -3462,6 +3511,10 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mTouchDelegateInfo.writeToParcel(parcel, flags);
+ }
+
if (DEBUG) {
fieldIndex--;
if (totalFields != fieldIndex) {
@@ -3543,6 +3596,10 @@ public class AccessibilityNodeInfo implements Parcelable {
if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = (other.mCollectionItemInfo != null)
? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+
+ final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
+ mTouchDelegateInfo = (otherInfo != null)
+ ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
}
/**
@@ -3665,6 +3722,10 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.readInt() == 1)
: null;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mTouchDelegateInfo = TouchDelegateInfo.CREATOR.createFromParcel(parcel);
+ }
+
mSealed = sealed;
}
@@ -3813,10 +3874,11 @@ public class AccessibilityNodeInfo implements Parcelable {
}
}
- private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
- return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
+ private static boolean canPerformRequestOverConnection(int connectionId,
+ int windowId, long accessibilityNodeId) {
+ return ((windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
&& (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
- && (mConnectionId != UNDEFINED_CONNECTION_ID));
+ && (connectionId != UNDEFINED_CONNECTION_ID));
}
@Override
@@ -3919,13 +3981,14 @@ public class AccessibilityNodeInfo implements Parcelable {
return builder.toString();
}
- private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
- if (!canPerformRequestOverConnection(accessibilityId)) {
+ private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
+ int windowId, long accessibilityId) {
+ if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+ return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
+ windowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
| FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
}
@@ -4896,6 +4959,176 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Class with information of touch delegated views and regions from {@link TouchDelegate} for
+ * the {@link AccessibilityNodeInfo}.
+ *
+ * @see AccessibilityNodeInfo#setTouchDelegateInfo(TouchDelegateInfo)
+ */
+ public static final class TouchDelegateInfo implements Parcelable {
+ private ArrayMap<Region, Long> mTargetMap;
+ // Two ids are initialized lazily in AccessibilityNodeInfo#getTouchDelegateInfo
+ private int mConnectionId;
+ private int mWindowId;
+
+ /**
+ * Create a new instance of {@link TouchDelegateInfo}.
+ *
+ * @param targetMap A map from regions (in view coordinates) to delegated views.
+ * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+ * Regions or Views.
+ */
+ public TouchDelegateInfo(@NonNull Map<Region, View> targetMap) {
+ Preconditions.checkArgument(!targetMap.isEmpty()
+ && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+ mTargetMap = new ArrayMap<>(targetMap.size());
+ for (final Region region : targetMap.keySet()) {
+ final View view = targetMap.get(region);
+ mTargetMap.put(region, (long) view.getAccessibilityViewId());
+ }
+ }
+
+ /**
+ * Create a new instance from target map.
+ *
+ * @param targetMap A map from regions (in view coordinates) to delegated views'
+ * accessibility id.
+ * @param doCopy True if shallow copy targetMap.
+ * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+ * Regions or Views.
+ */
+ TouchDelegateInfo(@NonNull ArrayMap<Region, Long> targetMap, boolean doCopy) {
+ Preconditions.checkArgument(!targetMap.isEmpty()
+ && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+ if (doCopy) {
+ mTargetMap = new ArrayMap<>(targetMap.size());
+ mTargetMap.putAll(targetMap);
+ } else {
+ mTargetMap = targetMap;
+ }
+ }
+
+ /**
+ * Set the connection ID.
+ *
+ * @param connectionId The connection id.
+ */
+ private void setConnectionId(int connectionId) {
+ mConnectionId = connectionId;
+ }
+
+ /**
+ * Set the window ID.
+ *
+ * @param windowId The window id.
+ */
+ private void setWindowId(int windowId) {
+ mWindowId = windowId;
+ }
+
+ /**
+ * Returns the number of touch delegate target region.
+ *
+ * @return Number of touch delegate target region.
+ */
+ public int getRegionCount() {
+ return mTargetMap.size();
+ }
+
+ /**
+ * Return the {@link Region} at the given index in the {@link TouchDelegateInfo}.
+ *
+ * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1.
+ * @return Returns the {@link Region} stored at the given index.
+ */
+ @NonNull
+ public Region getRegionAt(int index) {
+ return mTargetMap.keyAt(index);
+ }
+
+ /**
+ * Return the target {@link AccessibilityNodeInfo} for the given {@link Region}.
+ * <p>
+ * <strong>Note:</strong> This api can only be called from {@link AccessibilityService}.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
+ *
+ * @param region The region retrieved from {@link #getRegionAt(int)}.
+ * @return The target node associates with the given region.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getTargetForRegion(@NonNull Region region) {
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTargetMap.get(region));
+ }
+
+ /**
+ * Return the accessibility id of target node.
+ *
+ * @param region The region retrieved from {@link #getRegionAt(int)}.
+ * @return The accessibility id of target node.
+ *
+ * @hide
+ */
+ @TestApi
+ public long getAccessibilityIdForRegion(@NonNull Region region) {
+ return mTargetMap.get(region);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTargetMap.size());
+ for (int i = 0; i < mTargetMap.size(); i++) {
+ final Region region = mTargetMap.keyAt(i);
+ final Long accessibilityId = mTargetMap.valueAt(i);
+ region.writeToParcel(dest, flags);
+ dest.writeLong(accessibilityId);
+ }
+ }
+
+ /**
+ * @see android.os.Parcelable.Creator
+ */
+ public static final Parcelable.Creator<TouchDelegateInfo> CREATOR =
+ new Parcelable.Creator<TouchDelegateInfo>() {
+ @Override
+ public TouchDelegateInfo createFromParcel(Parcel parcel) {
+ final int size = parcel.readInt();
+ if (size == 0) {
+ return null;
+ }
+ final ArrayMap<Region, Long> targetMap = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final Region region = Region.CREATOR.createFromParcel(parcel);
+ final long accessibilityId = parcel.readLong();
+ targetMap.put(region, accessibilityId);
+ }
+ final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo(
+ targetMap, false);
+ return touchDelegateInfo;
+ }
+
+ @Override
+ public TouchDelegateInfo[] newArray(int size) {
+ return new TouchDelegateInfo[size];
+ }
+ };
+ }
+
+ /**
* @see android.os.Parcelable.Creator
*/
public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 08ed9d17fb77..e8e4b4aba0d4 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -477,7 +477,7 @@ public final class InputMethodManager {
if (view == null) {
return false;
}
- final int viewDisplayId = getDisplayId(view.getContext());
+ final int viewDisplayId = view.getContext().getDisplayId();
if (viewDisplayId != mDisplayId) {
Log.w(TAG, "b/117267690: Context mismatch found. view=" + view + " belongs to"
+ " displayId=" + viewDisplayId
@@ -779,11 +779,6 @@ public final class InputMethodManager {
mDummyInputConnection, this);
}
- private static int getDisplayId(Context context) {
- final Display display = context.getDisplay();
- return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
- }
-
/**
* Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
*
@@ -793,7 +788,7 @@ public final class InputMethodManager {
*/
@Nullable
public static InputMethodManager forContext(Context context) {
- final int displayId = getDisplayId(context);
+ final int displayId = context.getDisplayId();
// For better backward compatibility, we always use Looper.getMainLooper() for the default
// display case.
final Looper looper = displayId == Display.DEFAULT_DISPLAY
@@ -2690,7 +2685,7 @@ public final class InputMethodManager {
sb.append(",windowFocus=" + view.hasWindowFocus());
sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
sb.append(",window=" + view.getWindowToken());
- sb.append(",displayId=" + getDisplayId(view.getContext()));
+ sb.append(",displayId=" + view.getContext().getDisplayId());
sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
return sb.toString();
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 35ff6cc23499..8f17e96c144e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -42,6 +42,7 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.graphics.drawable.RippleDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -152,6 +153,7 @@ public class RemoteViews implements Parcelable, Filter {
private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18;
private static final int LAYOUT_PARAM_ACTION_TAG = 19;
private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
+ private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
/**
* Application that hosts the remote views.
@@ -1122,6 +1124,53 @@ public class RemoteViews implements Parcelable, Filter {
PorterDuff.Mode filterMode;
}
+ /**
+ * Equivalent to calling
+ * {@link RippleDrawable#setColor(ColorStateList)},
+ * on the {@link Drawable} of a given view.
+ * <p>
+ * The operation will be performed on the {@link Drawable} returned by the
+ * target {@link View#getBackground()}.
+ * <p>
+ */
+ private class SetRippleDrawableColor extends Action {
+
+ ColorStateList mColorStateList;
+
+ SetRippleDrawableColor(int id, ColorStateList colorStateList) {
+ this.viewId = id;
+ this.mColorStateList = colorStateList;
+ }
+
+ SetRippleDrawableColor(Parcel parcel) {
+ viewId = parcel.readInt();
+ mColorStateList = parcel.readParcelable(null);
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(viewId);
+ dest.writeParcelable(mColorStateList, 0);
+ }
+
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
+ final View target = root.findViewById(viewId);
+ if (target == null) return;
+
+ // Pick the correct drawable to modify for this view
+ Drawable targetDrawable = target.getBackground();
+
+ if (targetDrawable instanceof RippleDrawable) {
+ ((RippleDrawable) targetDrawable.mutate()).setColor(mColorStateList);
+ }
+ }
+
+ @Override
+ public int getActionTag() {
+ return SET_RIPPLE_DRAWABLE_COLOR_TAG;
+ }
+ }
+
private final class ViewContentNavigation extends Action {
final boolean mNext;
@@ -2394,6 +2443,8 @@ public class RemoteViews implements Parcelable, Filter {
return new LayoutParamAction(parcel);
case OVERRIDE_TEXT_COLORS_TAG:
return new OverrideTextColorsAction(parcel);
+ case SET_RIPPLE_DRAWABLE_COLOR_TAG:
+ return new SetRippleDrawableColor(parcel);
default:
throw new ActionException("Tag " + tag + " not found");
}
@@ -2855,6 +2906,22 @@ public class RemoteViews implements Parcelable, Filter {
/**
* @hide
+ * Equivalent to calling
+ * {@link RippleDrawable#setColor(ColorStateList)} on the {@link Drawable} of a given view,
+ * assuming it's a {@link RippleDrawable}.
+ * <p>
+ *
+ * @param viewId The id of the view that contains the target
+ * {@link RippleDrawable}
+ * @param colorStateList Specify a color for a
+ * {@link ColorStateList} for this drawable.
+ */
+ public void setRippleDrawableColor(int viewId, ColorStateList colorStateList) {
+ addAction(new SetRippleDrawableColor(viewId, colorStateList));
+ }
+
+ /**
+ * @hide
* Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}.
*
* @param viewId The id of the view whose tint should change
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9d06680c4c07..f74c2341d816 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3521,7 +3521,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Typeface mFontTypeface = null;
boolean mFontFamilyExplicit = false;
int mTypefaceIndex = -1;
- int mStyleIndex = -1;
+ int mTextStyle = 0;
int mFontWeight = -1;
boolean mAllCaps = false;
int mShadowColor = 0;
@@ -3547,7 +3547,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " mFontTypeface:" + mFontTypeface + "\n"
+ " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
+ " mTypefaceIndex:" + mTypefaceIndex + "\n"
- + " mStyleIndex:" + mStyleIndex + "\n"
+ + " mTextStyle:" + mTextStyle + "\n"
+ " mFontWeight:" + mFontWeight + "\n"
+ " mAllCaps:" + mAllCaps + "\n"
+ " mShadowColor:" + mShadowColor + "\n"
@@ -3672,7 +3672,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mFontFamilyExplicit = true;
break;
case com.android.internal.R.styleable.TextAppearance_textStyle:
- attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex);
+ attributes.mTextStyle = appearance.getInt(attr, attributes.mTextStyle);
break;
case com.android.internal.R.styleable.TextAppearance_textFontWeight:
attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight);
@@ -3742,7 +3742,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mFontFamily = null;
}
setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
- attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight);
+ attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight);
if (attributes.mShadowColor != 0) {
setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy,
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 10cf70215747..c256d57a6af6 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -137,7 +137,7 @@ public class Toast {
String pkg = mContext.getOpPackageName();
TN tn = mTN;
tn.mNextView = mNextView;
- final int displayId = mContext.getDisplay().getDisplayId();
+ final int displayId = mContext.getDisplayId();
try {
service.enqueueToast(pkg, tn, mDuration, displayId);
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index a8edfb6ec936..498de53b65e9 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -16,12 +16,17 @@
package com.android.internal.app;
+import static android.content.res.ResourceId.ID_NULL;
+
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Slog;
@@ -31,16 +36,19 @@ import com.android.internal.R;
public class SuspendedAppActivity extends AlertActivity
implements DialogInterface.OnClickListener {
- private static final String TAG = "SuspendedAppActivity";
- public static final String EXTRA_SUSPENDED_PACKAGE =
- "SuspendedAppActivity.extra.SUSPENDED_PACKAGE";
+ private static final String TAG = SuspendedAppActivity.class.getSimpleName();
+ private static final String PACKAGE_NAME = "com.android.internal.app";
+
+ public static final String EXTRA_SUSPENDED_PACKAGE = PACKAGE_NAME + ".extra.SUSPENDED_PACKAGE";
public static final String EXTRA_SUSPENDING_PACKAGE =
- "SuspendedAppActivity.extra.SUSPENDING_PACKAGE";
- public static final String EXTRA_DIALOG_MESSAGE = "SuspendedAppActivity.extra.DIALOG_MESSAGE";
+ PACKAGE_NAME + ".extra.SUSPENDING_PACKAGE";
+ public static final String EXTRA_DIALOG_INFO = PACKAGE_NAME + ".extra.DIALOG_INFO";
private Intent mMoreDetailsIntent;
private int mUserId;
private PackageManager mPm;
+ private Resources mSuspendingAppResources;
+ private SuspendDialogInfo mSuppliedDialogInfo;
private CharSequence getAppLabel(String packageName) {
try {
@@ -66,6 +74,65 @@ public class SuspendedAppActivity extends AlertActivity
return null;
}
+ private Drawable resolveIcon() {
+ final int iconId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getIconResId()
+ : ID_NULL;
+ if (iconId != ID_NULL && mSuspendingAppResources != null) {
+ try {
+ return mSuspendingAppResources.getDrawable(iconId, null);
+ } catch (Resources.NotFoundException nfe) {
+ Slog.e(TAG, "Could not resolve drawable resource id " + iconId);
+ }
+ }
+ return null;
+ }
+
+ private String resolveTitle() {
+ final int titleId = (mSuppliedDialogInfo != null) ? mSuppliedDialogInfo.getTitleResId()
+ : ID_NULL;
+ if (titleId != ID_NULL && mSuspendingAppResources != null) {
+ try {
+ return mSuspendingAppResources.getString(titleId);
+ } catch (Resources.NotFoundException nfe) {
+ Slog.e(TAG, "Could not resolve string resource id " + titleId);
+ }
+ }
+ return getString(R.string.app_suspended_title);
+ }
+
+ private String resolveDialogMessage(String suspendingPkg, String suspendedPkg) {
+ final CharSequence suspendedAppLabel = getAppLabel(suspendedPkg);
+ if (mSuppliedDialogInfo != null) {
+ final int messageId = mSuppliedDialogInfo.getDialogMessageResId();
+ final String message = mSuppliedDialogInfo.getDialogMessage();
+ if (messageId != ID_NULL && mSuspendingAppResources != null) {
+ try {
+ return mSuspendingAppResources.getString(messageId, suspendedAppLabel);
+ } catch (Resources.NotFoundException nfe) {
+ Slog.e(TAG, "Could not resolve string resource id " + messageId);
+ }
+ } else if (message != null) {
+ return String.format(getResources().getConfiguration().getLocales().get(0), message,
+ suspendedAppLabel);
+ }
+ }
+ return getString(R.string.app_suspended_default_message, suspendedAppLabel,
+ getAppLabel(suspendingPkg));
+ }
+
+ private String resolveNeutralButtonText() {
+ final int buttonTextId = (mSuppliedDialogInfo != null)
+ ? mSuppliedDialogInfo.getNeutralButtonTextResId() : ID_NULL;
+ if (buttonTextId != ID_NULL && mSuspendingAppResources != null) {
+ try {
+ return mSuspendingAppResources.getString(buttonTextId);
+ } catch (Resources.NotFoundException nfe) {
+ Slog.e(TAG, "Could not resolve string resource id " + buttonTextId);
+ }
+ }
+ return getString(R.string.app_suspended_more_details);
+ }
+
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -79,26 +146,26 @@ public class SuspendedAppActivity extends AlertActivity
finish();
return;
}
- final String suppliedMessage = intent.getStringExtra(EXTRA_DIALOG_MESSAGE);
final String suspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
final String suspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
- final CharSequence suspendedAppLabel = getAppLabel(suspendedPackage);
- final CharSequence dialogMessage;
- if (suppliedMessage == null) {
- dialogMessage = getString(R.string.app_suspended_default_message, suspendedAppLabel,
- getAppLabel(suspendingPackage));
- } else {
- dialogMessage = String.format(getResources().getConfiguration().getLocales().get(0),
- suppliedMessage, suspendedAppLabel);
+ mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO);
+ if (mSuppliedDialogInfo != null) {
+ try {
+ mSuspendingAppResources = mPm.getResourcesForApplicationAsUser(suspendingPackage,
+ mUserId);
+ } catch (PackageManager.NameNotFoundException ne) {
+ Slog.e(TAG, "Could not find resources for " + suspendingPackage, ne);
+ }
}
final AlertController.AlertParams ap = mAlertParams;
- ap.mTitle = getString(R.string.app_suspended_title);
- ap.mMessage = dialogMessage;
+ ap.mIcon = resolveIcon();
+ ap.mTitle = resolveTitle();
+ ap.mMessage = resolveDialogMessage(suspendingPackage, suspendedPackage);
ap.mPositiveButtonText = getString(android.R.string.ok);
mMoreDetailsIntent = getMoreDetailsActivity(suspendingPackage, suspendedPackage, mUserId);
if (mMoreDetailsIntent != null) {
- ap.mNeutralButtonText = getString(R.string.app_suspended_more_details);
+ ap.mNeutralButtonText = resolveNeutralButtonText();
}
ap.mPositiveButtonListener = ap.mNeutralButtonListener = this;
setupAlert();
@@ -116,11 +183,11 @@ public class SuspendedAppActivity extends AlertActivity
}
public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- String suspendingPackage, String dialogMessage, int userId) {
+ String suspendingPackage, SuspendDialogInfo dialogInfo, int userId) {
return new Intent()
.setClassName("android", SuspendedAppActivity.class.getName())
.putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
- .putExtra(EXTRA_DIALOG_MESSAGE, dialogMessage)
+ .putExtra(EXTRA_DIALOG_INFO, dialogInfo)
.putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 0080ace230a2..d4c451e3ffff 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -72,7 +72,8 @@ public class AmbientDisplayConfiguration {
}
public boolean wakeLockScreenGestureAvailable() {
- return !TextUtils.isEmpty(wakeLockScreenSensorType());
+ return mContext.getResources()
+ .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
}
public boolean wakeScreenGestureEnabled(int user) {
@@ -92,10 +93,6 @@ public class AmbientDisplayConfiguration {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
- public String wakeLockScreenSensorType() {
- return mContext.getResources().getString(R.string.config_dozeWakeLockScreenSensorType);
- }
-
public String wakeScreenSensorType() {
return mContext.getResources().getString(R.string.config_dozeWakeScreenSensorType);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 33b9ff7cee4f..017da550c9d3 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5330,6 +5330,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
@@ -5341,6 +5342,7 @@ public class BatteryStatsImpl extends BatteryStats {
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index e4724ff45b9e..8dc97fe86eb3 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -66,6 +66,7 @@ public class LooperStats implements Looper.Observer {
session = session == null ? new DispatchSession() : session;
session.startTimeMicro = getElapsedRealtimeMicro();
session.cpuStartMicro = getThreadTimeMicro();
+ session.systemUptimeMillis = getSystemUptimeMillis();
return session;
}
@@ -85,12 +86,18 @@ public class LooperStats implements Looper.Observer {
entry.messageCount++;
if (session != DispatchSession.NOT_SAMPLED) {
entry.recordedMessageCount++;
- long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
- long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+ final long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+ final long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
entry.totalLatencyMicro += latency;
entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
entry.cpuUsageMicro += cpuUsage;
entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+ if (msg.getWhen() > 0) {
+ final long delay = Math.max(0L, session.systemUptimeMillis - msg.getWhen());
+ entry.delayMillis += delay;
+ entry.maxDelayMillis = Math.max(entry.maxDelayMillis, delay);
+ entry.recordedDelayMessageCount++;
+ }
}
}
}
@@ -206,6 +213,10 @@ public class LooperStats implements Looper.Observer {
return SystemClock.elapsedRealtimeNanos() / 1000;
}
+ protected long getSystemUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
protected boolean shouldCollectDetailedData() {
return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
}
@@ -214,6 +225,7 @@ public class LooperStats implements Looper.Observer {
static final DispatchSession NOT_SAMPLED = new DispatchSession();
public long startTimeMicro;
public long cpuStartMicro;
+ public long systemUptimeMillis;
}
private static class Entry {
@@ -228,6 +240,9 @@ public class LooperStats implements Looper.Observer {
public long maxLatencyMicro;
public long cpuUsageMicro;
public long maxCpuUsageMicro;
+ public long recordedDelayMessageCount;
+ public long delayMillis;
+ public long maxDelayMillis;
Entry(Message msg, boolean isInteractive) {
this.workSourceUid = msg.workSourceUid;
@@ -251,6 +266,9 @@ public class LooperStats implements Looper.Observer {
maxLatencyMicro = 0;
cpuUsageMicro = 0;
maxCpuUsageMicro = 0;
+ delayMillis = 0;
+ maxDelayMillis = 0;
+ recordedDelayMessageCount = 0;
}
static int idFor(Message msg, boolean isInteractive) {
@@ -281,6 +299,9 @@ public class LooperStats implements Looper.Observer {
public final long maxLatencyMicros;
public final long cpuUsageMicros;
public final long maxCpuUsageMicros;
+ public final long maxDelayMillis;
+ public final long delayMillis;
+ public final long recordedDelayMessageCount;
ExportedEntry(Entry entry) {
this.workSourceUid = entry.workSourceUid;
@@ -301,6 +322,9 @@ public class LooperStats implements Looper.Observer {
this.maxLatencyMicros = entry.maxLatencyMicro;
this.cpuUsageMicros = entry.cpuUsageMicro;
this.maxCpuUsageMicros = entry.maxCpuUsageMicro;
+ this.delayMillis = entry.delayMillis;
+ this.maxDelayMillis = entry.maxDelayMillis;
+ this.recordedDelayMessageCount = entry.recordedDelayMessageCount;
}
}
}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index bf31c7d8ad85..1ee4269d974b 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -29,7 +29,6 @@ import android.util.Slog;
import com.android.internal.util.FastPrintWriter;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.File;
import java.io.FileInputStream;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 87515173e8de..3b7ce0a22b18 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1387,7 +1387,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private int getOptionsPanelGravity() {
try {
return WindowManagerHolder.sWindowManager.getPreferredOptionsPanelGravity(
- getContext().getDisplay().getDisplayId());
+ getContext().getDisplayId());
} catch (RemoteException ex) {
Log.e(TAG, "Couldn't getOptionsPanelGravity; using default", ex);
return Gravity.CENTER | Gravity.BOTTOM;
@@ -3642,7 +3642,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (!mIsWatching) {
try {
WindowManagerHolder.sWindowManager.watchRotation(this,
- phoneWindow.getContext().getDisplay().getDisplayId());
+ phoneWindow.getContext().getDisplayId());
mHandler = new Handler();
mIsWatching = true;
} catch (RemoteException ex) {
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 989c58ba6060..27c2478bd420 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -101,7 +101,7 @@ public class LatencyTracker {
public static LatencyTracker getInstance(Context context) {
if (sLatencyTracker == null) {
- sLatencyTracker = new LatencyTracker(context);
+ sLatencyTracker = new LatencyTracker(context.getApplicationContext());
}
return sLatencyTracker;
}
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 9bf094891f3b..7a0174946671 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -18,6 +18,7 @@ package com.android.internal.widget;
import android.annotation.AttrRes;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.StyleRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -50,6 +51,7 @@ public class AlertDialogLayout extends LinearLayout {
super(context);
}
+ @UnsupportedAppUsage
public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index ab8be33599fa..0ca67438c5c3 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -40,6 +41,7 @@ public class ButtonBarLayout extends LinearLayout {
private int mMinimumHeight = 0;
+ @UnsupportedAppUsage
public ButtonBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 7ea3d6b5bff0..405436c53ff0 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
@@ -37,6 +38,7 @@ public class DialogTitle extends TextView {
super(context, attrs, defStyleAttr);
}
+ @UnsupportedAppUsage
public DialogTitle(Context context, AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 0a787b99c0ac..d68e8f88fc5a 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -331,13 +331,11 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
- // Allow Product to customize system configs around libs, features, permissions and apps
- int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
- ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+ // Allow Product to customize all system configs
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow /product_services to customize system configs around libs, features, permissions
// and apps.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index c2ca2fc35631..ed6445d92b13 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -84,8 +84,6 @@ cc_library_shared {
"android_view_VelocityTracker.cpp",
"android_text_AndroidCharacter.cpp",
"android_text_Hyphenator.cpp",
- "android_text_LineBreaker.cpp",
- "android_text_MeasuredParagraph.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
"android_os_HidlSupport.cpp",
@@ -161,6 +159,8 @@ cc_library_shared {
"android/graphics/pdf/PdfEditor.cpp",
"android/graphics/pdf/PdfRenderer.cpp",
"android/graphics/pdf/PdfUtils.cpp",
+ "android/graphics/text/LineBreaker.cpp",
+ "android/graphics/text/MeasuredText.cpp",
"android_media_AudioRecord.cpp",
"android_media_AudioSystem.cpp",
"android_media_AudioTrack.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6b55ed6d2289..c05bad2a4332 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -145,6 +145,8 @@ extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
+extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
+extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_DisplayListCanvas(JNIEnv* env);
extern int register_android_view_TextureLayer(JNIEnv* env);
@@ -185,8 +187,6 @@ extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_Hyphenator(JNIEnv *env);
-extern int register_android_text_MeasuredParagraph(JNIEnv* env);
-extern int register_android_text_LineBreaker(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
@@ -1336,8 +1336,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_res_ApkAssets),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
- REG_JNI(register_android_text_MeasuredParagraph),
- REG_JNI(register_android_text_LineBreaker),
REG_JNI(register_android_view_InputDevice),
REG_JNI(register_android_view_KeyCharacterMap),
REG_JNI(register_android_os_Process),
@@ -1415,6 +1413,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_pdf_PdfDocument),
REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
+ REG_JNI(register_android_graphics_text_MeasuredText),
+ REG_JNI(register_android_graphics_text_LineBreaker),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 263596954954..c32de0a5737e 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -21,6 +21,10 @@
#include <hwui/Bitmap.h>
#include <renderthread/RenderProxy.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+
+#include <private/android/AHardwareBufferHelpers.h>
+
#include "core_jni_helpers.h"
#include <jni.h>
@@ -1104,8 +1108,7 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit
static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
- // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
- // format and SRGB color space.
+ // Bitmap::createFrom currently assumes SRGB color space for RGBA images.
// To support any color space, we need to pass an additional ColorSpace argument to
// java Bitmap.createHardwareBitmap.
sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
@@ -1116,6 +1119,22 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}
+static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
+ jfloatArray xyzD50, jobject transferParameters) {
+ SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+ SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+ sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
+ AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
+ hardwareBuffer);
+ sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
+ sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, colorSpace);
+ if (!bitmap.get()) {
+ ALOGW("failed to create hardware bitmap from hardware buffer");
+ return NULL;
+ }
+ return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
+}
+
static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
LocalScopedBitmap bitmapHandle(bitmapPtr);
LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
@@ -1195,6 +1214,8 @@ static const JNINativeMethod gBitmapMethods[] = {
(void*)Bitmap_copyPreserveInternalConfig },
{ "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
(void*) Bitmap_createHardwareBitmap },
+ { "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
+ (void*) Bitmap_wrapHardwareBufferBitmap },
{ "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
(void*) Bitmap_createGraphicBufferHandle },
{ "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace },
diff --git a/core/jni/android_text_LineBreaker.cpp b/core/jni/android/graphics/text/LineBreaker.cpp
index 543910727ffd..e1f2f2b8e069 100644
--- a/core/jni/android_text_LineBreaker.cpp
+++ b/core/jni/android/graphics/text/LineBreaker.cpp
@@ -168,8 +168,9 @@ static const JNINativeMethod gMethods[] = {
{"nGetReleaseResultFunc", "()J", (void*)nGetReleaseResultFunc},
};
-int register_android_text_LineBreaker(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/text/NativeLineBreaker", gMethods, NELEM(gMethods));
+int register_android_graphics_text_LineBreaker(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/graphics/text/LineBreaker", gMethods,
+ NELEM(gMethods));
}
}
diff --git a/core/jni/android_text_MeasuredParagraph.cpp b/core/jni/android/graphics/text/MeasuredText.cpp
index 18f509c7ec60..0bfadb407a93 100644
--- a/core/jni/android_text_MeasuredParagraph.cpp
+++ b/core/jni/android/graphics/text/MeasuredText.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "MeasuredParagraph"
+#define LOG_TAG "MeasuredText"
#include "GraphicsJNI.h"
#include "unicode/locid.h"
@@ -83,7 +83,7 @@ static void nAddReplacementRun(JNIEnv* /* unused */, jclass /* unused */, jlong
}
// Regular JNI
-static jlong nBuildNativeMeasuredParagraph(JNIEnv* env, jclass /* unused */, jlong builderPtr,
+static jlong nBuildMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr,
jcharArray javaText, jboolean computeHyphenation,
jboolean computeLayout) {
ScopedCharArrayRO text(env, javaText);
@@ -147,7 +147,7 @@ static const JNINativeMethod gMTBuilderMethods[] = {
{"nInitBuilder", "()J", (void*) nInitBuilder},
{"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
{"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
- {"nBuildNativeMeasuredParagraph", "(J[CZZ)J", (void*) nBuildNativeMeasuredParagraph},
+ {"nBuildMeasuredText", "(J[CZZ)J", (void*) nBuildMeasuredText},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
};
@@ -160,10 +160,10 @@ static const JNINativeMethod gMTMethods[] = {
{"nGetCharWidthAt", "(JI)F", (void*) nGetCharWidthAt}, // Critical Native
};
-int register_android_text_MeasuredParagraph(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/text/NativeMeasuredParagraph",
+int register_android_graphics_text_MeasuredText(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/graphics/text/MeasuredText",
gMTMethods, NELEM(gMTMethods))
- + RegisterMethodsOrDie(env, "android/text/NativeMeasuredParagraph$Builder",
+ + RegisterMethodsOrDie(env, "android/graphics/text/MeasuredText$Builder",
gMTBuilderMethods, NELEM(gMTBuilderMethods));
}
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b70485d9a0ea..92235ad494a7 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,6 +23,10 @@
namespace {
+int getCanLoadSystemLibraries_native() {
+ return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
+}
+
void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {
ScopedUtfChars pathChars(env, path);
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
@@ -51,6 +55,7 @@ void setDebugLayers_native(JNIEnv* env, jobject clazz, jstring layers) {
}
const JNINativeMethod g_methods[] = {
+ { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index ecad6c027391..d023d22473c8 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -23,6 +23,7 @@
#include <atomic>
#include <fcntl.h>
#include <inttypes.h>
+#include <mutex>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -69,6 +70,7 @@ static struct bindernative_offsets_t
// Class state.
jclass mClass;
jmethodID mExecTransact;
+ jmethodID mGetInterfaceDescriptor;
// Object state.
jfieldID mObject;
@@ -326,8 +328,32 @@ protected:
env->DeleteGlobalRef(mObject);
}
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
+ const String16& getInterfaceDescriptor() const override
+ {
+ call_once(mPopulateDescriptor, [this] {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+
+ ALOGV("getInterfaceDescriptor() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
+
+ jstring descriptor = (jstring)env->CallObjectMethod(mObject, gBinderOffsets.mGetInterfaceDescriptor);
+
+ if (descriptor == nullptr) {
+ return;
+ }
+
+ static_assert(sizeof(jchar) == sizeof(char16_t), "");
+ const jchar* descriptorChars = env->GetStringChars(descriptor, nullptr);
+ const char16_t* rawDescriptor = reinterpret_cast<const char16_t*>(descriptorChars);
+ jsize rawDescriptorLen = env->GetStringLength(descriptor);
+ mDescriptor = String16(rawDescriptor, rawDescriptorLen);
+ env->ReleaseStringChars(descriptor, descriptorChars);
+ });
+
+ return mDescriptor;
+ }
+
+ status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
JNIEnv* env = javavm_to_jnienv(mVM);
@@ -376,7 +402,7 @@ protected:
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
- virtual status_t dump(int fd, const Vector<String16>& args)
+ status_t dump(int fd, const Vector<String16>& args) override
{
return 0;
}
@@ -384,6 +410,9 @@ protected:
private:
JavaVM* const mVM;
jobject const mObject; // GlobalRef to Java Binder
+
+ mutable std::once_flag mPopulateDescriptor;
+ mutable String16 mDescriptor;
};
// ----------------------------------------------------------------------------
@@ -926,6 +955,8 @@ static int int_register_android_os_Binder(JNIEnv* env)
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
+ gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
+ "()Ljava/lang/String;");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b70177ffab9a..2e1e130d8375 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -339,6 +339,17 @@ static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong transactionObj,
transaction->setMatrix(ctrl, dsdx, dtdx, dtdy, dsdy);
}
+static void nativeSetColorTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jfloatArray fMatrix, jfloatArray fTranslation) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+ SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
+ float* floatMatrix = env->GetFloatArrayElements(fMatrix, 0);
+ mat3 matrix(static_cast<float const*>(floatMatrix));
+ float* floatTranslation = env->GetFloatArrayElements(fTranslation, 0);
+ vec3 translation(floatTranslation[0], floatTranslation[1], floatTranslation[2]);
+ transaction->setColorTransform(surfaceControl, matrix, translation);
+}
+
static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jint l, jint t, jint r, jint b) {
@@ -849,6 +860,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetColor },
{"nativeSetMatrix", "(JJFFFF)V",
(void*)nativeSetMatrix },
+ {"nativeSetColorTransform", "(JJ[F[F)V",
+ (void*)nativeSetColorTransform },
{"nativeSetFlags", "(JJII)V",
(void*)nativeSetFlags },
{"nativeSetWindowCrop", "(JJIIII)V",
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index ed42e2ee51a5..30a9a01c3448 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,6 +7,8 @@ jinyithu@google.com
joeo@google.com
kwekua@google.com
singhtejinder@google.com
+yanglu@google.com
+yaochen@google.com
# Frameworks
ogunwale@google.com
diff --git a/core/proto/android/internal/powerprofile.proto b/core/proto/android/internal/powerprofile.proto
index 9dd5e7ee556c..b0c8b5638a72 100644
--- a/core/proto/android/internal/powerprofile.proto
+++ b/core/proto/android/internal/powerprofile.proto
@@ -35,7 +35,7 @@ message PowerProfileProto {
repeated double core_power = 5;
}
- repeated CpuCluster cpu_cluster = 41;
+ repeated CpuCluster cpu_cluster = 40;
optional double wifi_scan = 4;
@@ -85,27 +85,27 @@ message PowerProfileProto {
optional double ambient_display = 27;
- optional double screen_on = 29;
+ optional double screen_on = 28;
- optional double radio_on = 30;
+ optional double radio_on = 29;
- optional double radio_scanning = 31;
+ optional double radio_scanning = 30;
- optional double radio_active = 32;
+ optional double radio_active = 31;
- optional double screen_full = 33;
+ optional double screen_full = 32;
- optional double audio = 34;
+ optional double audio = 33;
- optional double video = 35;
+ optional double video = 34;
- optional double flashlight = 36;
+ optional double flashlight = 35;
- optional double memory = 37;
+ optional double memory = 36;
- optional double camera = 38;
+ optional double camera = 37;
- optional double wifi_batched_scan = 39;
+ optional double wifi_batched_scan = 38;
- optional double battery_capacity = 40;
+ optional double battery_capacity = 39;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a02602ee5d99..47dbc0716c94 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -397,9 +397,10 @@ message GlobalSettingsProto {
// Ordered GPU debug layer list
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
// App will load ANGLE instead of native GLES drivers.
optional SettingProto angle_enabled_app = 3;
+ // App that can provide layer libraries.
+ optional SettingProto debug_layer_app = 4;
}
optional Gpu gpu = 59;
diff --git a/proto/src/stats_enums.proto b/core/proto/android/stats/enums.proto
index 6c892cfeae6c..2320a01b324c 100644
--- a/proto/src/stats_enums.proto
+++ b/core/proto/android/stats/enums.proto
@@ -16,8 +16,7 @@
syntax = "proto2";
-package android.os.statsd;
-option java_package = "com.android.os";
+package android.stats;
option java_outer_classname = "StatsEnums";
enum EventType {
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 32975a5550f1..fba2e51937b3 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -61,3 +61,64 @@ enum SignalStrengthEnum {
SIGNAL_STRENGTH_GOOD = 3;
SIGNAL_STRENGTH_GREAT = 4;
}
+
+
+enum ServiceStateEnum {
+ /**
+ * Normal operation condition, the phone is registered
+ * with an operator either in home network or in roaming.
+ */
+ SERVICE_STATE_IN_SERVICE = 0;
+
+ /**
+ * Phone is not registered with any operator, the phone
+ * can be currently searching a new operator to register to, or not
+ * searching to registration at all, or registration is denied, or radio
+ * signal is not available.
+ */
+ SERVICE_STATE_OUT_OF_SERVICE = 1;
+
+ /**
+ * The phone is registered and locked. Only emergency numbers are allowed. {@more}
+ */
+ SERVICE_STATE_EMERGENCY_ONLY = 2;
+
+ /**
+ * Radio of telephony is explicitly powered off.
+ */
+ SERVICE_STATE_POWER_OFF = 3;
+}
+
+enum SimStateEnum {
+ SIM_STATE_UNKNOWN = 0;
+ /** SIM card state: no SIM card is available in the device */
+ SIM_STATE_ABSENT = 1;
+ /** SIM card state: Locked: requires the user's SIM PIN to unlock */
+ SIM_STATE_PIN_REQUIRED = 2;
+ /** SIM card state: Locked: requires the user's SIM PUK to unlock */
+ SIM_STATE_PUK_REQUIRED = 3;
+ /** SIM card state: Locked: requires a network PIN to unlock */
+ SIM_STATE_NETWORK_LOCKED = 4;
+ /** SIM card state: Ready */
+ SIM_STATE_READY = 5;
+ /** SIM card state: SIM Card is NOT READY */
+ SIM_STATE_NOT_READY = 6;
+ /** SIM card state: SIM Card Error, permanently disabled */
+ SIM_STATE_PERM_DISABLED = 7;
+ /** SIM card state: SIM Card Error, present but faulty */
+ SIM_STATE_CARD_IO_ERROR = 8;
+ /** SIM card state: SIM Card restricted, present but not usable due to
+ * carrier restrictions.
+ */
+ SIM_STATE_CARD_RESTRICTED = 9;
+ /**
+ * SIM card state: Loaded: SIM card applications have been loaded
+ * @hide
+ */
+ SIM_STATE_LOADED = 10;
+ /**
+ * SIM card state: SIM Card is present
+ * @hide
+ */
+ SIM_STATE_PRESENT = 11;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3f012de53be..1ae5f03a2f04 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -138,7 +138,6 @@
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
<protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
- <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
@@ -1151,6 +1150,28 @@
android:protectionLevel="dangerous|instant"/>
<!-- ====================================================================== -->
+ <!-- Permissions for activity recognition -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for permissions that are associated with activity recognition.
+ TODO(zezeozue). STOPSHIP: Add icon -->
+ <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
+ android:label="@string/permgrouplab_activityRecognition"
+ android:description="@string/permgroupdesc_activityRecognition"
+ android:request="@string/permgrouprequest_activityRecognition"
+ android:priority="1000" />
+
+ <!-- Allows an application to recognize physical activity.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ACTIVITY_RECOGNITION"
+ android:permissionGroup="android.permission-group.ACTIVITY_RECOGNITION"
+ android:label="@string/permlab_activityRecognition"
+ android:description="@string/permdesc_activityRecognition"
+ android:protectionLevel="dangerous|instant" />
+
+ <!-- ====================================================================== -->
<!-- Permissions for accessing the UCE Service -->
<!-- ====================================================================== -->
@@ -1546,6 +1567,7 @@
<!-- Allows SetupWizard to call methods in Networking services
<p>Not for use by any other third-party or privileged applications.
+ @SystemApi
@hide This should only be used by SetupWizard.
-->
<permission android:name="android.permission.NETWORK_SETUP_WIZARD"
@@ -2748,7 +2770,7 @@
android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to use
- {@link android.view.WindowManager.LayoutsParams#PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
+ {@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
to hide non-system-overlay windows.
<p>Not for use by third-party applications.
@hide
diff --git a/core/res/res/layout/notification_material_media_action.xml b/core/res/res/layout/notification_material_media_action.xml
index 900ca2dd7667..dd79a0bb1817 100644
--- a/core/res/res/layout/notification_material_media_action.xml
+++ b/core/res/res/layout/notification_material_media_action.xml
@@ -18,7 +18,6 @@
<ImageButton
xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.Material.Button.Borderless.Small"
- android:id="@+id/action0"
android:layout_width="@dimen/media_notification_action_button_size"
android:layout_height="@dimen/media_notification_action_button_size"
android:paddingBottom="8dp"
@@ -28,4 +27,5 @@
android:layout_marginEnd="2dp"
android:gravity="center"
android:background="@drawable/notification_material_media_action_background"
+ android:visibility="gone"
/>
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index b4e26483a2ad..5cb93eb9319a 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -59,7 +59,26 @@
android:orientation="horizontal"
android:layoutDirection="ltr"
style="@style/NotificationMediaActionContainer" >
- <!-- media buttons will be added here -->
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action0"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action1"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action2"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action3"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action4"
+ />
</LinearLayout>
</LinearLayout>
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 3a0912bd2a90..01b0866f428c 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -65,7 +65,18 @@
android:layoutDirection="ltr"
android:orientation="horizontal"
>
- <!-- media buttons will be added here -->
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action0"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action1"
+ />
+ <include
+ layout="@layout/notification_material_media_action"
+ android:id="@+id/action2"
+ />
</LinearLayout>
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index c8d4d05a3507..931674a8c0cb 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -50,7 +50,9 @@ easier.
{@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
-->
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
- <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/>
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault">
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ </style>
<!-- Theme for the dialog shown when an app crashes or ANRs. -->
<style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8b73b6768479..7b01e8a9e15a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -697,6 +697,10 @@
<!-- Wifi driver supports IEEE80211AC for softap -->
<bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
+ <!-- Indicates that local-only hotspot should be brought up at 5GHz. This option is
+ for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
+ <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
+
<!-- Flag indicating whether we should enable the automatic brightness.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
@@ -2113,8 +2117,8 @@
<!-- Type of the long press sensor. Empty if long press is not supported. -->
<string name="config_dozeLongPressSensorType" translatable="false"></string>
- <!-- Type of sensor that wakes up the lock screen. Empty if not supported. -->
- <string name="config_dozeWakeLockScreenSensorType" translatable="false"></string>
+ <!-- If the sensor that wakes up the lock screen is available or not. -->
+ <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
<!-- Type of the wake up sensor. Empty if not supported. -->
<string name="config_dozeWakeScreenSensorType" translatable="false"></string>
@@ -3367,22 +3371,22 @@
<bool name="config_sendPackageName">false</bool>
<!-- Name for the set of keys associating package names -->
- <string name="config_help_package_name_key" translatable="false"></string>
+ <string name="config_helpPackageNameKey" translatable="false"></string>
<!-- Name for the set of values of package names -->
- <string name="config_help_package_name_value" translatable="false"></string>
+ <string name="config_helpPackageNameValue" translatable="false"></string>
<!-- Intent key for the package name keys -->
- <string name="config_help_intent_extra_key" translatable="false"></string>
+ <string name="config_helpIntentExtraKey" translatable="false"></string>
<!-- Intent key for package name values -->
- <string name="config_help_intent_name_key" translatable="false"></string>
+ <string name="config_helpIntentNameKey" translatable="false"></string>
<!-- Intent key for the package name keys -->
- <string name="config_feedback_intent_extra_key" translatable="false"></string>
+ <string name="config_feedbackIntentExtraKey" translatable="false"></string>
<!-- Intent key for package name values -->
- <string name="config_feedback_intent_name_key" translatable="false"></string>
+ <string name="config_feedbackIntentNameKey" translatable="false"></string>
<!-- The apps that need to be hidden when they are disabled -->
<string-array name="config_hideWhenDisabled_packageNames"></string-array>
@@ -3487,7 +3491,7 @@
<string name="config_headlineFontFamilyMedium">@string/font_family_button_material</string>
<!-- Size of icon shown beside a preference locked by admin -->
- <dimen name="config_restricted_icon_size">@dimen/restricted_icon_size_material</dimen>
+ <dimen name="config_restrictedIconSize">@dimen/restricted_icon_size_material</dimen>
<string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2e42e4ac27f3..95517186fe9e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2930,17 +2930,17 @@
<public-group type="string" first-id="0x0104001b">
<!-- @hide @SystemApi -->
- <public name="config_help_package_name_key" />
+ <public name="config_helpPackageNameKey" />
<!-- @hide @SystemApi -->
- <public name="config_help_package_name_value" />
+ <public name="config_helpPackageNameValue" />
<!-- @hide @SystemApi -->
- <public name="config_help_intent_extra_key" />
+ <public name="config_helpIntentExtraKey" />
<!-- @hide @SystemApi -->
- <public name="config_help_intent_name_key" />
+ <public name="config_helpIntentNameKey" />
<!-- @hide @SystemApi -->
- <public name="config_feedback_intent_extra_key" />
+ <public name="config_feedbackIntentExtraKey" />
<!-- @hide @SystemApi -->
- <public name="config_feedback_intent_name_key" />
+ <public name="config_feedbackIntentNameKey" />
</public-group>
<public-group type="bool" first-id="0x01110000">
@@ -2950,7 +2950,7 @@
<public-group type="dimen" first-id="0x01050007">
<!-- @hide @SystemApi -->
- <public name="config_restricted_icon_size" />
+ <public name="config_restrictedIconSize" />
</public-group>
<!-- ===============================================================
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1e3aeae8e3c4..fa4406185218 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -734,6 +734,14 @@
<string name="permgrouprequest_microphone">Allow
&lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to record audio?</string>
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+ <string name="permgrouplab_activityRecognition">Activity recognition</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+ <string name="permgroupdesc_activityRecognition">recognize activity</string>
+ <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
+ <string name="permgrouprequest_activityRecognition">Allow
+ &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to recognize your physical activity?</string>
+
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_camera">Camera</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1151,6 +1159,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_sim_communication">Allows the app to send commands to the SIM. This is very dangerous.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]-->
+ <string name="permlab_activityRecognition">recognize physical activity</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
+ <string name="permdesc_activityRecognition">This app can recognize your physical activity.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_camera">take pictures and videos</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1418,6 +1431,9 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
+ <!-- Title shown when the system-provided biometric dialog is shown, asking the user to authenticate. [CHAR LIMIT=40] -->
+ <string name="biometric_dialog_default_title">Application <xliff:g id="app" example="Gmail">%s</xliff:g> wants to authenticate.</string>
+
<!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
<string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
@@ -5005,33 +5021,33 @@
<!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
- <string name="autofill_save_title">Save to &lt;b><xliff:g id="label" example="MyPass">%1$s</xliff:g>&lt;/b>?</string>
+ <string name="autofill_save_title">Save to <b><xliff:g id="label" example="MyPass">%1$s</xliff:g></b>?</string>
<!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
- by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%2$s</xliff:g>&lt;/b>?</string>
+ by an autofill service, and the service knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%2$s</xliff:g></b>?</string>
<!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
- by an autofill service, and the service does knows what the activity represents, and it represents 2 types of
+ by an autofill service, and the service knows what the activity represents, and it represents 2 types of
data (for example, password and credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_save_title_with_2types">Save <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%3$s</xliff:g>&lt;/b>?</string>
+ <string name="autofill_save_title_with_2types">Save <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%3$s</xliff:g></b>?</string>
<!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
- by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
+ by an autofill service, and the service knows what the activity represents, and it represents 3 types of
data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_save_title_with_3types">Save <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>
+ <string name="autofill_save_title_with_3types">Save <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>?</string>
<!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
- by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
- <string name="autofill_update_title">Update to &lt;b><xliff:g id="label" example="MyPass">%1$s</xliff:g>&lt;/b>?</string>
+ in an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
+ <string name="autofill_update_title">Update in <b><xliff:g id="label" example="MyPass">%1$s</xliff:g></b>?</string>
<!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
- by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_update_title_with_type">Update <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%2$s</xliff:g>&lt;/b>?</string>
+ in an autofill service, and the service knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+ <string name="autofill_update_title_with_type">Update <xliff:g id="type" example="Credit Card">%1$s</xliff:g> in <b><xliff:g id="label" example="MyPass">%2$s</xliff:g></b>?</string>
<!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
- by an autofill service, and the service does knows what the activity represents, and it represents 2 types of
+ in an autofill service, and the service knows what the activity represents, and it represents 2 types of
data (for example, password and credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_update_title_with_2types">Update <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%3$s</xliff:g>&lt;/b>?</string>
+ <string name="autofill_update_title_with_2types">Update <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> in <b><xliff:g id="label" example="MyPass">%3$s</xliff:g></b>?</string>
<!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
- by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
+ in an autofill service, and the service knows what the activity represents, and it represents 3 types of
data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
- <string name="autofill_update_title_with_3types">Update <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>
+ <string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> ?</string>
<!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a7b6dde12628..97bfcc14fc42 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -186,6 +186,8 @@
<java-symbol type="id" name="action0" />
<java-symbol type="id" name="action1" />
<java-symbol type="id" name="action2" />
+ <java-symbol type="id" name="action3" />
+ <java-symbol type="id" name="action4" />
<java-symbol type="id" name="big_picture" />
<java-symbol type="id" name="big_text" />
<java-symbol type="id" name="chronometer" />
@@ -1873,6 +1875,7 @@
<java-symbol type="bool" name="config_wifi_background_scan_support" />
<java-symbol type="bool" name="config_wifi_dual_band_support" />
<java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" />
+ <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
<java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
<java-symbol type="bool" name="config_wimaxEnabled" />
<java-symbol type="bool" name="show_ongoing_ime_switcher" />
@@ -2394,6 +2397,7 @@
<java-symbol type="string" name="config_keyguardComponent" />
<!-- Biometric messages -->
+ <java-symbol type="string" name="biometric_dialog_default_title" />
<java-symbol type="string" name="biometric_error_hw_unavailable" />
<java-symbol type="string" name="biometric_not_recognized" />
@@ -3269,17 +3273,17 @@
<java-symbol type="integer" name="default_data_warning_level_mb" />
<java-symbol type="bool" name="config_useVideoPauseWorkaround" />
<java-symbol type="bool" name="config_sendPackageName" />
- <java-symbol type="string" name="config_help_package_name_key" />
- <java-symbol type="string" name="config_help_package_name_value" />
- <java-symbol type="string" name="config_help_intent_extra_key" />
- <java-symbol type="string" name="config_help_intent_name_key" />
- <java-symbol type="string" name="config_feedback_intent_extra_key" />
- <java-symbol type="string" name="config_feedback_intent_name_key" />
+ <java-symbol type="string" name="config_helpPackageNameKey" />
+ <java-symbol type="string" name="config_helpPackageNameValue" />
+ <java-symbol type="string" name="config_helpIntentExtraKey" />
+ <java-symbol type="string" name="config_helpIntentNameKey" />
+ <java-symbol type="string" name="config_feedbackIntentExtraKey" />
+ <java-symbol type="string" name="config_feedbackIntentNameKey" />
<java-symbol type="array" name="config_hideWhenDisabled_packageNames" />
<java-symbol type="string" name="config_dozeLongPressSensorType" />
- <java-symbol type="string" name="config_dozeWakeLockScreenSensorType" />
+ <java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" />
<java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
<java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index fb78b3b0533a..7b3d940b91f3 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -109,12 +109,12 @@
<!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
visual voicemail code for Orange: 21101 -->
- <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366" />
+ <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051" />
<!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
visual voicemail code for EE: 887 -->
- <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726" />
+ <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
<!-- Georgia: 4 digits, known premium codes listed -->
<shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -189,11 +189,14 @@
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
+ <!-- Nigeria -->
+ <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
+
<!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
<!-- New Zealand: 3-4 digits, known premium codes listed -->
- <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
+ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
<!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="pe" pattern="\\d{4,5}" free="9963" />
@@ -209,7 +212,7 @@
<!-- Portugal: 5 digits, plus EU:
http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
- <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262" />
+ <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262|12666" />
<!-- Qatar: 1-5 digits (standard system default, not country specific) -->
<shortcode country="qa" pattern="\\d{1,5}" free="92451" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 4a58f885ff08..2989df83866c 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -16,6 +16,7 @@
package com.android.bandwidthtest;
+import android.app.UiAutomation;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
@@ -74,7 +75,13 @@ public class BandwidthTest extends InstrumentationTestCase {
Log.v(LOG_TAG, "Initialized mConnectionUtil");
mUid = Process.myUid();
mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
- mDeviceId = mTManager.getDeviceId();
+ final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+ try {
+ uiAutomation.adoptShellPermissionIdentity();
+ mDeviceId = mTManager.getDeviceId();
+ } finally {
+ uiAutomation.dropShellPermissionIdentity();
+ }
}
@Override
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index e0d53933b33b..041fb7eeb6b3 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -47,7 +47,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- conscrypt \
telephony-common \
org.apache.http.legacy \
android.test.base \
@@ -67,10 +66,6 @@ LOCAL_RESOURCE_DIR := $(FrameworkCoreTests_intermediates) $(LOCAL_PATH)/res
# Disable AAPT2 because the hacks below depend on the AAPT rules implementation
LOCAL_USE_AAPT2 := false
-# When AAPT2 is enabled it will need --warn-manifest-validation to fix:
-# frameworks/base/core/tests/coretests/AndroidManifest.xml:26: error: unknown element <meta-data> found.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-# LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
# Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
index 97275931be4b..3f163def9ce0 100644
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ b/core/tests/coretests/apks/install_multi_package/Android.mk
@@ -8,10 +8,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := install_multi_package
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml:46: error: unexpected element <package> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
#include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
index 679327c9b0df..745b4d32ccc4 100644
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.mk
@@ -6,9 +6,5 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := install_verifier_bad
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_bad/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
index 7d621b32900b..150fd8dd8701 100644
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_good/Android.mk
@@ -6,9 +6,5 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := install_verifier_good
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_good/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index bdb3e089444f..fe51a39d3cd2 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -15,7 +15,9 @@
*/
package android.app.assist;
+import static android.view.View.AUTOFILL_TYPE_TEXT;
import static android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO;
+import static android.view.View.IMPORTANT_FOR_AUTOFILL_YES;
import static com.google.common.truth.Truth.assertThat;
@@ -27,7 +29,9 @@ import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.text.InputFilter;
import android.util.Log;
+import android.view.autofill.AutofillId;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -68,6 +72,16 @@ public class AssistStructureTest {
// Cannot be much big because it could hang test due to blocking GC
private static final int NUMBER_SMALL_VIEWS = 10_000;
+ // Autofill field constants
+ private static final AutofillId AUTOFILL_ID = new AutofillId(2);
+ private static final String AUTOFILL_HINTS = "hints";
+ private static final int MIN_TEXT_EMS = 5;
+ private static final int MAX_TEXT_EMS = 17;
+ private static final int MAX_TEXT_LENGTH = 23;
+
+ // ViewNodeBuilder structure for editing autofill fields
+ private AssistStructure.ViewNodeBuilder mBuilder;
+
private EmptyLayoutActivity mActivity;
private final ActivityTestRule<EmptyLayoutActivity> mActivityTestRule =
@@ -211,6 +225,12 @@ public class AssistStructureTest {
private EditText newSmallView() {
EditText view = new EditText(mContext);
view.setText("I AM GROOT");
+ view.setMinEms(MIN_TEXT_EMS);
+ view.setMaxEms(MAX_TEXT_EMS);
+ view.setAutofillId(AUTOFILL_ID);
+ view.setAutofillHints(AUTOFILL_HINTS);
+ view.setFilters(new InputFilter[] { new InputFilter.LengthFilter(MAX_TEXT_LENGTH) });
+ view.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
return view;
}
@@ -220,6 +240,16 @@ public class AssistStructureTest {
assertThat(view.getIdEntry()).isNull();
assertThat(view.getAutofillId()).isNotNull();
assertThat(view.getText().toString()).isEqualTo("I AM GROOT");
+
+ assertThat(view.getAutofillType()).isEqualTo(AUTOFILL_TYPE_TEXT);
+
+ // fields controlled by mAutofillFlag
+ assertThat(view.getAutofillId().getViewId()).isEqualTo(2);
+ assertThat(view.getAutofillHints()[0]).isEqualTo(AUTOFILL_HINTS);
+ assertThat(view.getMinTextEms()).isEqualTo(MIN_TEXT_EMS);
+ assertThat(view.getMaxTextEms()).isEqualTo(MAX_TEXT_EMS);
+ assertThat(view.getMaxTextLength()).isEqualTo(MAX_TEXT_LENGTH);
+ assertThat(view.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_YES);
}
private EditText newBigView() {
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
new file mode 100644
index 000000000000..c8a3098690be
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.ActivityThread;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowManager;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ContextTest {
+ @Test
+ public void testDisplayIdForSystemContext() {
+ final Context systemContext =
+ ActivityThread.currentActivityThread().getSystemContext();
+
+ assertEquals(systemContext.getDisplay().getDisplayId(), systemContext.getDisplayId());
+ }
+
+ @Test
+ public void testDisplayIdForTestContext() {
+ final Context testContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ assertEquals(testContext.getDisplay().getDisplayId(), testContext.getDisplayId());
+ }
+
+ @Test
+ public void testDisplayIdForDefaultDisplayContext() {
+ final Context testContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final WindowManager wm = testContext.getSystemService(WindowManager.class);
+ final Context defaultDisplayContext =
+ testContext.createDisplayContext(wm.getDefaultDisplay());
+
+ assertEquals(defaultDisplayContext.getDisplay().getDisplayId(),
+ defaultDisplayContext.getDisplayId());
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 584257b1f6a9..e248a7771cab 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -45,7 +45,7 @@ import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
import org.junit.After;
import org.junit.Assert;
@@ -63,7 +63,7 @@ public class DexMetadataHelperTest {
@Before
public void setUp() {
- mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest");
+ mTmpDir = TestIoUtils.createTemporaryDirectory("DexMetadataHelperTest");
}
@After
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 20fe16251854..80281b63c4a1 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -48,7 +48,6 @@ import android.provider.DocumentsContract.Document;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
import libcore.io.Streams;
import com.google.android.collect.Sets;
@@ -95,7 +94,7 @@ public class FileUtilsTest {
@After
public void tearDown() throws Exception {
- IoUtils.deleteContents(mDir);
+ FileUtils.deleteContents(mDir);
FileUtils.deleteContents(mTarget);
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 014ae1f47f30..632c37fd54d2 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -450,6 +450,7 @@ public class SettingsBackupTest {
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.ANGLE_ENABLED_APP,
+ Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
@@ -543,6 +544,7 @@ public class SettingsBackupTest {
Settings.Secure.BACKUP_ENABLED,
Settings.Secure.BACKUP_PROVISIONED,
Settings.Secure.BACKUP_TRANSPORT,
+ Settings.Secure.CALL_REDIRECTION_DEFAULT_APPLICATION,
Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
Settings.Secure.CARRIER_APPS_HANDLED,
Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index f3d6013b8ee3..3d15eb9577b5 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -73,7 +73,7 @@ public class MeasuredParagraphTest {
assertEquals(0, mt.getWidths().size());
assertEquals(0, mt.getSpanEndCache().size());
assertEquals(0, mt.getFontMetrics().size());
- assertNull(mt.getNativeMeasuredParagraph());
+ assertNull(mt.getMeasuredText());
// Recycle it
MeasuredParagraph mt2 = MeasuredParagraph.buildForBidi("_VVV_", 1, 4, RTL, mt);
@@ -85,7 +85,7 @@ public class MeasuredParagraphTest {
assertEquals(0, mt2.getWidths().size());
assertEquals(0, mt2.getSpanEndCache().size());
assertEquals(0, mt2.getFontMetrics().size());
- assertNull(mt.getNativeMeasuredParagraph());
+ assertNull(mt.getMeasuredText());
mt2.recycle();
}
@@ -107,7 +107,7 @@ public class MeasuredParagraphTest {
assertEquals(10, mt.getWidths().get(2), 0);
assertEquals(0, mt.getSpanEndCache().size());
assertEquals(0, mt.getFontMetrics().size());
- assertNull(mt.getNativeMeasuredParagraph());
+ assertNull(mt.getMeasuredText());
// Recycle it
MeasuredParagraph mt2 =
@@ -124,7 +124,7 @@ public class MeasuredParagraphTest {
assertEquals(5, mt2.getWidths().get(2), 0);
assertEquals(0, mt2.getSpanEndCache().size());
assertEquals(0, mt2.getFontMetrics().size());
- assertNull(mt.getNativeMeasuredParagraph());
+ assertNull(mt.getMeasuredText());
mt2.recycle();
}
@@ -144,7 +144,7 @@ public class MeasuredParagraphTest {
assertEquals(1, mt.getSpanEndCache().size());
assertEquals(3, mt.getSpanEndCache().get(0));
assertNotEquals(0, mt.getFontMetrics().size());
- assertNotNull(mt.getNativeMeasuredParagraph());
+ assertNotNull(mt.getMeasuredText());
// Recycle it
MeasuredParagraph mt2 =
@@ -159,7 +159,7 @@ public class MeasuredParagraphTest {
assertEquals(1, mt2.getSpanEndCache().size());
assertEquals(4, mt2.getSpanEndCache().get(0));
assertNotEquals(0, mt2.getFontMetrics().size());
- assertNotNull(mt.getNativeMeasuredParagraph());
+ assertNotNull(mt.getMeasuredText());
mt2.recycle();
}
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index f8e3b4dfec56..872b71a5faa6 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -117,7 +117,7 @@ public class DateUtilsTest {
@Test
public void testFormatSameDayTime() {
// This test assumes a default DateFormat.is24Hour setting.
- DateFormat.is24Hour = null;
+ DateFormat.set24HourTimePref(null);
Date date = new Date(109, 0, 19, 3, 30, 15);
long fixedTime = date.getTime();
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index c8d994c4f6c1..8e4f2cd2fbff 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -103,6 +103,18 @@ public class DisplayCutoutTest {
equalTo(new Rect[]{ZERO_RECT, boundTop, ZERO_RECT, boundBottom}));
}
+ @Test
+ public void testExtractBoundsFromList_nullBoundingRects() {
+ Rect safeInsets = new Rect(0, 0, 0, 0);
+ assertThat(extractBoundsFromList(safeInsets, null /* boundingRects */),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
+
+ @Test
+ public void testExtractBoundsFromList_nullSafeInsets() {
+ assertThat(extractBoundsFromList(null /* safeInsets */, Collections.emptyList()),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
@Test
public void hasCutout() throws Exception {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 69d2828f20bc..506e5447a239 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -45,7 +45,7 @@ public class AccessibilityNodeInfoTest {
// The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
// See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
// and assertAccessibilityNodeInfoCleared in that class.
- private static final int NUM_MARSHALLED_PROPERTIES = 33;
+ private static final int NUM_MARSHALLED_PROPERTIES = 34;
/**
* The number of properties that are purposely not marshalled
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0c8dd9d6ed59..f637b7c7ec32 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -77,9 +77,13 @@ public final class LooperStatsTest {
Message message = mHandlerFirst.obtainMessage(1000);
message.workSourceUid = 1000;
+ message.when = looperStats.getSystemUptimeMillis();
+
+ looperStats.tickUptime(30);
Object token = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(10);
+ looperStats.tickUptime(200);
looperStats.messageDispatched(token, message);
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -98,6 +102,10 @@ public final class LooperStatsTest {
assertThat(entry.maxLatencyMicros).isEqualTo(100);
assertThat(entry.cpuUsageMicros).isEqualTo(10);
assertThat(entry.maxCpuUsageMicros).isEqualTo(10);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
+ assertThat(entry.delayMillis).isEqualTo(30);
+ assertThat(entry.maxDelayMillis).isEqualTo(30);
+
}
@Test
@@ -215,6 +223,56 @@ public final class LooperStatsTest {
}
@Test
+ public void testDispatchDelayIsRecorded() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+
+ // Dispatched right on time.
+ Message message1 = mHandlerFirst.obtainMessage(1000);
+ message1.when = looperStats.getSystemUptimeMillis();
+ Object token1 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token1, message1);
+
+ // Dispatched 100ms late.
+ Message message2 = mHandlerFirst.obtainMessage(1000);
+ message2.when = looperStats.getSystemUptimeMillis() - 100;
+ Object token2 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token2, message2);
+
+ // No target dispatching time.
+ Message message3 = mHandlerFirst.obtainMessage(1000);
+ message3.when = 0;
+ Object token3 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token3, message3);
+
+ // Dispatched too soon (should never happen).
+ Message message4 = mHandlerFirst.obtainMessage(1000);
+ message4.when = looperStats.getSystemUptimeMillis() + 200;
+ Object token4 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token4, message4);
+
+ // Dispatched 300ms late.
+ Message message5 = mHandlerFirst.obtainMessage(1000);
+ message5.when = looperStats.getSystemUptimeMillis() - 300;
+ Object token5 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token5, message5);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(1);
+
+ LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.messageCount).isEqualTo(5);
+ assertThat(entry.recordedMessageCount).isEqualTo(5);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(4);
+ assertThat(entry.delayMillis).isEqualTo(400);
+ assertThat(entry.maxDelayMillis).isEqualTo(300);
+ }
+
+ @Test
public void testDataNotCollectedBeforeDeviceStateSet() {
TestableLooperStats looperStats = new TestableLooperStats(1, 100);
looperStats.setDeviceState(null);
@@ -385,6 +443,7 @@ public final class LooperStatsTest {
private int mCount;
private long mRealtimeMicros;
private long mThreadTimeMicros;
+ private long mUptimeMillis;
private int mSamplingInterval;
TestableLooperStats(int samplingInterval, int sizeCap) {
@@ -401,6 +460,10 @@ public final class LooperStatsTest {
mThreadTimeMicros += micros;
}
+ void tickUptime(long millis) {
+ mUptimeMillis += millis;
+ }
+
@Override
protected long getElapsedRealtimeMicro() {
return INITIAL_MICROS + mRealtimeMicros;
@@ -412,6 +475,11 @@ public final class LooperStatsTest {
}
@Override
+ protected long getSystemUptimeMillis() {
+ return INITIAL_MICROS / 1000 + mUptimeMillis;
+ }
+
+ @Override
protected boolean shouldCollectDetailedData() {
return mCount++ % mSamplingInterval == 0;
}
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
index edad4b26314c..97a3d0078e26 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -20,4 +20,6 @@ LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
index 3fae8e19fc5b..a3470255997d 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -20,4 +20,6 @@ LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
index c352c0550034..e4819e138eba 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -20,4 +20,6 @@ LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index ab3faf0b158a..8656781e31e5 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -21,6 +21,8 @@ LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
my_package_prefix := com.android.server.om.hosttest.framework_overlay
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 114c2285c008..44f8737da2c1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -139,6 +139,7 @@ applications that come with the platform
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
</privapp-permissions>
<privapp-permissions package="com.android.permissioncontroller">
@@ -322,7 +323,9 @@ applications that come with the platform
<permission name="android.permission.PACKAGE_USAGE_STATS" />
<permission name="android.permission.READ_FRAME_BUFFER"/>
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REAL_GET_TASKS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 0885a05c74f3..ea0a109c3a04 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -549,7 +549,7 @@ public abstract class BaseCanvas {
contextStart - paraStart,
contextEnd - contextStart,
x, y, isRtl, paint.getNativeInstance(),
- mp.getNativeMeasuredParagraph().getNativePtr());
+ mp.getMeasuredText().getNativePtr());
return;
}
}
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index fb30ca2d4090..4de7ca708eb6 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -520,7 +520,7 @@ public class BaseRecordingCanvas extends Canvas {
contextStart - paraStart,
contextEnd - contextStart,
x, y, isRtl, paint.getNativeInstance(),
- mp.getNativeMeasuredParagraph().getNativePtr());
+ mp.getMeasuredText().getNativePtr());
return;
}
}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 9cbbf4ef366f..1cd756f9f73f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -24,6 +24,7 @@ import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
+import android.hardware.HardwareBuffer;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -724,6 +725,48 @@ public final class Bitmap implements Parcelable {
}
/**
+ * Create a hardware bitmap backed by a {@link HardwareBuffer}.
+ *
+ * <p>The passed HardwareBuffer's usage flags must contain
+ * {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}.
+ *
+ * <p>The bitmap will keep a reference to the buffer so that callers can safely close the
+ * HardwareBuffer without affecting the Bitmap. However the HardwareBuffer must not be
+ * modified while a wrapped Bitmap is accessing it. Doing so will result in undefined behavior.
+ *
+ * @param hardwareBuffer The HardwareBuffer to wrap.
+ * @param colorSpace The color space of the bitmap. Must be a {@link ColorSpace.Rgb} colorspace.
+ * If null, SRGB is assumed.
+ * @return A bitmap wrapping the buffer, or null if there was a problem creating the bitmap.
+ * @throws IllegalArgumentException if the HardwareBuffer has an invalid usage, or an invalid
+ * colorspace is given.
+ */
+ @Nullable
+ public static Bitmap wrapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer,
+ @Nullable ColorSpace colorSpace) {
+ if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
+ throw new IllegalArgumentException("usage flags must contain USAGE_GPU_SAMPLED_IMAGE.");
+ }
+ int format = hardwareBuffer.getFormat();
+ ColorSpace.Rgb rgb = null;
+ if (colorSpace != null) {
+ if (!(colorSpace instanceof ColorSpace.Rgb)) {
+ throw new IllegalArgumentException("colorSpace must be an RGB color space");
+ }
+ rgb = (ColorSpace.Rgb) colorSpace;
+ } else {
+ rgb = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+ }
+ ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
+ if (parameters == null) {
+ throw new IllegalArgumentException("colorSpace must use an ICC "
+ + "parametric transfer function");
+ }
+ ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
+ return nativeWrapHardwareBufferBitmap(hardwareBuffer, d50.getTransform(), parameters);
+ }
+
+ /**
* Creates a new bitmap, scaled from an existing bitmap, when possible. If the
* specified width and height are the same as the current width and height of
* the source bitmap, the source bitmap is returned and no new bitmap is
@@ -2118,6 +2161,9 @@ public final class Bitmap implements Parcelable {
private static native int nativeGetAllocationByteCount(long nativeBitmap);
private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
+ private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
+ @Size(9) float[] xyzD50,
+ ColorSpace.Rgb.TransferParameters p);
private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
private static native boolean nativeIsSRGB(long nativePtr);
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 8414d6a6b866..2e1d81a294e9 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -472,8 +472,8 @@ public abstract class ColorSpace {
* <tr>
* <td>Electro-optical transfer function (EOTF)</td>
* <td colspan="4">\(\begin{equation}
- * C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.039 \\\
- * \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.039 \end{cases}
+ * C_{linear} = \begin{cases}\frac{C_{DisplayP3}}{12.92} & C_{sRGB} \lt 0.04045 \\\
+ * \left( \frac{C_{DisplayP3} + 0.055}{1.055} \right) ^{2.4} & C_{sRGB} \ge 0.04045 \end{cases}
* \end{equation}\)
* </td>
* </tr>
@@ -1484,7 +1484,7 @@ public abstract class ColorSpace {
"Display P3",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
ILLUMINANT_D65,
- new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.039, 2.4),
+ new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
Named.DISPLAY_P3.ordinal()
);
sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
@@ -2525,9 +2525,7 @@ public abstract class ColorSpace {
gamma == 1.0 ? DoubleUnaryOperator.identity() :
x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
min, max, id);
- mTransferParameters = gamma == 1.0 ?
- new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0f), gamma) :
- new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+ mTransferParameters = new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
}
/**
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 7efe5220873e..f41cc7ee5095 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,6 @@ import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -570,7 +569,7 @@ public final class Icon implements Parcelable {
* Version of createWithResource that takes Resources. Do not use.
* @hide
*/
- @SystemApi
+ @UnsupportedAppUsage
public static Icon createWithResource(Resources res, @DrawableRes int resId) {
if (res == null) {
throw new IllegalArgumentException("Resource must not be null.");
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 3821bc7ab063..21ce1b8392d2 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -27,7 +27,6 @@ import android.system.Os;
import android.system.OsConstants;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.IOException;
diff --git a/core/java/android/text/NativeLineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 94e10e89acbd..8d38f961f402 100644
--- a/core/java/android/text/NativeLineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.text;
+package android.graphics.text;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -32,11 +32,57 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * A native implementation of the line breaker.
- * TODO: Consider to make this class public.
- * @hide
+ * Provides automatic line breaking for a <em>single</em> paragraph.
+ *
+ * <p>
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * String text = "Hello, Android.";
+ *
+ * // Prepare the measured text
+ * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+ * .addStyleRun(paint, 0, text.length(), false) // Use paint for whole paragraph.
+ * .build();
+ *
+ * LineBreaker lb = new LineBreaker.Builder()
+ * // Use simple line breaker
+ * .setBreakStrategy(LineBreaker.BREAK_STRATEGY_SIMPLE)
+ * // Do not add hyphenation.
+ * .setHyphenationFrequency(LineBreaker.HYPHENATION_FREQUENCY_NONE)
+ * // Build the LineBreaker
+ * .build();
+ *
+ * ParagraphConstraints c = new ParagraphConstraints();
+ * c.setWidth(240); // Set the line wieth as 1024px
+ *
+ * // Do the line breaking
+ * Result r = lb.computeLineBreaks(mt, c, 0);
+ *
+ * // Compute the total height of the text.
+ * float totalHeight = 0;
+ * for (int i = 0; i < r.getLineCount(); ++i) { // iterate over the lines
+ * totalHeight += r.getLineDescent(i) - r.getLineAscent(i);
+ * }
+ *
+ * // Draw text to the canvas
+ * Bitmap bmp = new Bitmap.createBitmap(240, totalHeight, Bitmap.Config.ARGB_8888);
+ * Canvas c = new Canvas(bmp);
+ * float yOffset = 0f;
+ * int prevOffset = 0;
+ * for (int i = 0; i < r.getLineCount(); ++i) { // iterate over the lines
+ * int nextOffset = r.getLineBreakOffset(i);
+ * c.drawText(text, prevOffset, nextOffset, 0f, yOffset, paint);
+ *
+ * prevOffset = nextOffset;
+ * yOffset += r.getLineDescent(i) - r.getLineAscent(i);
+ * }
+ * </code>
+ * </pre>
+ * </p>
*/
-public class NativeLineBreaker {
+public class LineBreaker {
+ /** @hide */
@IntDef(prefix = { "BREAK_STRATEGY_" }, value = {
BREAK_STRATEGY_SIMPLE,
BREAK_STRATEGY_HIGH_QUALITY,
@@ -46,25 +92,33 @@ public class NativeLineBreaker {
public @interface BreakStrategy {}
/**
- * Value for break strategy indicating simple line breaking. Automatic hyphens are not added
- * (though soft hyphens are respected), and modifying text generally doesn't affect the layout
- * before it (which yields a more consistent user experience when editing), but layout may not
- * be the highest quality.
+ * Value for break strategy indicating simple line breaking.
+ *
+ * The line breaker puts words to the line as much as possible and breaks line if no more words
+ * can fit into the same line. Automatic hyphens are only added when a line has a single word
+ * and that word is longer than line width. This is the fastest break strategy and ideal for
+ * editor.
*/
public static final int BREAK_STRATEGY_SIMPLE = 0;
/**
- * Value for break strategy indicating high quality line breaking, including automatic
- * hyphenation and doing whole-paragraph optimization of line breaks.
+ * Value for break strategy indicating high quality line breaking.
+ *
+ * With this option line breaker does whole-paragraph optimization for more readable text, and
+ * also applies automatic hyphenation when required.
*/
public static final int BREAK_STRATEGY_HIGH_QUALITY = 1;
/**
- * Value for break strategy indicating balanced line breaking. The breaks are chosen to
- * make all lines as close to the same length as possible, including automatic hyphenation.
+ * Value for break strategy indicating balanced line breaking.
+ *
+ * The line breaker does whole-paragraph optimization for making all lines similar length, and
+ * also applies automatic hyphenation when required. This break strategy is good for small
+ * screen devices such as watch screens.
*/
public static final int BREAK_STRATEGY_BALANCED = 2;
+ /** @hide */
@IntDef(prefix = { "HYPHENATION_FREQUENCY_" }, value = {
HYPHENATION_FREQUENCY_NORMAL,
HYPHENATION_FREQUENCY_FULL,
@@ -74,28 +128,32 @@ public class NativeLineBreaker {
public @interface HyphenationFrequency {}
/**
- * Value for hyphenation frequency indicating no automatic hyphenation. Useful
- * for backward compatibility, and for cases where the automatic hyphenation algorithm results
- * in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the
- * layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
- * as suggestions for potential line breaks.
+ * Value for hyphenation frequency indicating no automatic hyphenation.
+ *
+ * Using this option disables auto hyphenation which results in better text layout performance.
+ * A word may be broken without hyphens when a line has a single word and that word is longer
+ * than line width. Soft hyphens are ignored and will not be used as suggestions for potential
+ * line breaks.
*/
public static final int HYPHENATION_FREQUENCY_NONE = 0;
/**
- * Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
- * is a conservative default. Useful for informal cases, such as short sentences or chat
+ * Value for hyphenation frequency indicating a light amount of automatic hyphenation.
+ *
+ * This hyphenation frequency is useful for informal cases, such as short sentences or chat
* messages.
*/
public static final int HYPHENATION_FREQUENCY_NORMAL = 1;
/**
- * Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
- * in typography. Useful for running text and where it's important to put the maximum amount of
- * text in a screen with limited space.
+ * Value for hyphenation frequency indicating the full amount of automatic hyphenation.
+ *
+ * This hyphenation frequency is useful for running text and where it's important to put the
+ * maximum amount of text in a screen with limited space.
*/
public static final int HYPHENATION_FREQUENCY_FULL = 2;
+ /** @hide */
@IntDef(prefix = { "JUSTIFICATION_MODE_" }, value = {
JUSTIFICATION_MODE_NONE,
JUSTIFICATION_MODE_INTER_WORD
@@ -114,7 +172,7 @@ public class NativeLineBreaker {
public static final int JUSTIFICATION_MODE_INTER_WORD = 1;
/**
- * A builder class of NativeLineBreaker.
+ * Helper class for creating a {@link LineBreaker}.
*/
public static class Builder {
private @BreakStrategy int mBreakStrategy = BREAK_STRATEGY_SIMPLE;
@@ -123,12 +181,10 @@ public class NativeLineBreaker {
private @Nullable int[] mIndents = null;
/**
- * Construct a builder class.
- */
- public Builder() {}
-
- /**
* Set break strategy.
+ *
+ * You can change the line breaking behavior by setting break strategy. The default value is
+ * {@link #BREAK_STRATEGY_SIMPLE}.
*/
public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
mBreakStrategy = breakStrategy;
@@ -137,6 +193,9 @@ public class NativeLineBreaker {
/**
* Set hyphenation frequency.
+ *
+ * You can change the amount of automatic hyphenation used. The default value is
+ * {@link #HYPHENATION_FREQUENCY_NONE}.
*/
public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) {
mHyphenationFrequency = hyphenationFrequency;
@@ -145,6 +204,10 @@ public class NativeLineBreaker {
/**
* Set whether the text is justified.
+ *
+ * By setting {@link #JUSTIFICATION_MODE_INTER_WORD}, the line breaker will change the
+ * internal parameters for justification.
+ * The default value is {@link #JUSTIFICATION_MODE_NONE}
*/
public Builder setJustified(@JustificationMode int justified) {
mJustified = justified;
@@ -152,9 +215,11 @@ public class NativeLineBreaker {
}
/**
- * Set indents for entire text.
+ * Set indents.
*
- * Sets the total (left + right) indents in pixel per lines.
+ * The supplied array provides the total amount of indentation per line, in pixel. This
+ * amount is the sum of both left and right indentations. For lines past the last element in
+ * the array, the indentation amount of the last element is used.
*/
public Builder setIndents(@Nullable int[] indents) {
mIndents = indents;
@@ -162,11 +227,12 @@ public class NativeLineBreaker {
}
/**
- * Returns the NativeLineBreaker with given parameters.
+ * Build a new LineBreaker with given parameters.
+ *
+ * You can reuse the Builder instance even after calling this method.
*/
- NativeLineBreaker build() {
- return new NativeLineBreaker(mBreakStrategy, mHyphenationFrequency, mJustified,
- mIndents);
+ public LineBreaker build() {
+ return new LineBreaker(mBreakStrategy, mHyphenationFrequency, mJustified, mIndents);
}
}
@@ -184,8 +250,10 @@ public class NativeLineBreaker {
/**
* Set width for this paragraph.
+ *
+ * @see #getWidth()
*/
- public void setWidth(@FloatRange(from = 0.0f) float width) {
+ public void setWidth(@Px @FloatRange(from = 0.0f) float width) {
mWidth = width;
}
@@ -194,9 +262,11 @@ public class NativeLineBreaker {
*
* @param firstWidth the line width of the starting of the paragraph
* @param firstWidthLineCount the number of lines that applies the firstWidth
+ * @see #getFirstWidth()
+ * @see #getFirstWidthLineCount()
*/
- public void setIndent(@FloatRange(from = 0.0f) float firstWidth,
- @IntRange(from = 0) int firstWidthLineCount) {
+ public void setIndent(@Px @FloatRange(from = 0.0f) float firstWidth,
+ @Px @IntRange(from = 0) int firstWidthLineCount) {
mFirstWidth = firstWidth;
mFirstWidthLineCount = firstWidthLineCount;
}
@@ -206,16 +276,21 @@ public class NativeLineBreaker {
*
* @param tabStops the array of pixels of tap stopping position
* @param defaultTabStop pixels of the default tab stopping position
+ * @see #getTabStops()
+ * @see #getDefaultTabStop()
*/
- public void setTabStops(@Nullable int[] tabStops, @IntRange(from = 0) int defaultTabStop) {
+ public void setTabStops(@Nullable int[] tabStops,
+ @Px @IntRange(from = 0) int defaultTabStop) {
mVariableTabStops = tabStops;
mDefaultTabStop = defaultTabStop;
}
/**
* Return the width for this paragraph in pixels.
+ *
+ * @see #setWidth(float)
*/
- public @FloatRange(from = 0.0f) float getWidth() {
+ public @Px @FloatRange(from = 0.0f) float getWidth() {
return mWidth;
}
@@ -224,7 +299,7 @@ public class NativeLineBreaker {
*
* @see #setIndent(float, int)
*/
- public @FloatRange(from = 0.0f) float getFirstWidth() {
+ public @Px @FloatRange(from = 0.0f) float getFirstWidth() {
return mFirstWidth;
}
@@ -233,7 +308,7 @@ public class NativeLineBreaker {
*
* @see #setIndent(float, int)
*/
- public @IntRange(from = 0) int getFirstWidthLineCount() {
+ public @Px @IntRange(from = 0) int getFirstWidthLineCount() {
return mFirstWidthLineCount;
}
@@ -251,13 +326,14 @@ public class NativeLineBreaker {
*
* @see #setTabStop(int[], int)
*/
- public @IntRange(from = 0) int getDefaultTabStop() {
+ public @Px @IntRange(from = 0) int getDefaultTabStop() {
return mDefaultTabStop;
}
}
/**
- * A result object of a line breaking
+ * Holds the result of the {@link LineBreaker#computeLineBreaks line breaking algorithm}.
+ * @see LineBreaker#computeLineBreaks
*/
public static class Result {
// Following two contstant must be synced with minikin's line breaker.
@@ -274,7 +350,7 @@ public class NativeLineBreaker {
}
/**
- * Returns a number of line count.
+ * Returns the number of lines in the paragraph.
*
* @return number of lines
*/
@@ -283,7 +359,7 @@ public class NativeLineBreaker {
}
/**
- * Returns a break offset of the line.
+ * Returns character offset of the break for a given line.
*
* @param lineIndex an index of the line.
* @return the break offset.
@@ -293,17 +369,17 @@ public class NativeLineBreaker {
}
/**
- * Returns a width of the line in pixels.
+ * Returns width of a given line in pixels.
*
* @param lineIndex an index of the line.
- * @return a width of the line in pixexls
+ * @return width of the line in pixels
*/
public @Px float getLineWidth(@IntRange(from = 0) int lineIndex) {
return nGetLineWidth(mPtr, lineIndex);
}
/**
- * Returns an entier font ascent of the line in pixels.
+ * Returns font ascent of the line in pixels.
*
* @param lineIndex an index of the line.
* @return an entier font ascent of the line in pixels.
@@ -313,7 +389,7 @@ public class NativeLineBreaker {
}
/**
- * Returns an entier font descent of the line in pixels.
+ * Returns font descent of the line in pixels.
*
* @param lineIndex an index of the line.
* @return an entier font descent of the line in pixels.
@@ -337,6 +413,7 @@ public class NativeLineBreaker {
*
* @param lineIndex an index of the line.
* @return a packed hyphen edit for the line.
+ *
* @see android.text.Hyphenator#unpackStartHyphenEdit(int)
* @see android.text.Hyphenator#unpackEndHyphenEdit(int)
* @see android.text.Hyphenator#packHyphenEdit(int,int)
@@ -347,14 +424,14 @@ public class NativeLineBreaker {
}
private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
- NativeLineBreaker.class.getClassLoader(), nGetReleaseFunc(), 64);
+ LineBreaker.class.getClassLoader(), nGetReleaseFunc(), 64);
private final long mNativePtr;
/**
* Use Builder instead.
*/
- private NativeLineBreaker(@BreakStrategy int breakStrategy,
+ private LineBreaker(@BreakStrategy int breakStrategy,
@HyphenationFrequency int hyphenationFrequency, @JustificationMode int justify,
@Nullable int[] indents) {
mNativePtr = nInit(breakStrategy, hyphenationFrequency,
@@ -372,7 +449,7 @@ public class NativeLineBreaker {
* @param lineNumber a line number of this paragraph
*/
public Result computeLineBreaks(
- @NonNull NativeMeasuredParagraph measuredPara,
+ @NonNull MeasuredText measuredPara,
@NonNull ParagraphConstraints constraints,
@IntRange(from = 0) int lineNumber) {
return new Result(nComputeLineBreaks(
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
new file mode 100644
index 000000000000..36e7028915f3
--- /dev/null
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.text;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Px;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Result of text shaping of the single paragraph string.
+ */
+public class MeasuredText {
+ private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ MeasuredText.class.getClassLoader(), nGetReleaseFunc(), 1024);
+
+ private long mNativePtr;
+ private @NonNull char[] mChars;
+
+ // Use builder instead.
+ private MeasuredText(long ptr, @NonNull char[] chars) {
+ mNativePtr = ptr;
+ mChars = chars;
+ }
+
+ /**
+ * Returns the characters in the paragraph used to compute this MeasuredText instance.
+ */
+ public @NonNull char[] getChars() {
+ return mChars;
+ }
+
+ /**
+ * Returns the width of a given range.
+ *
+ * @param start an inclusive start index of the range
+ * @param end an exclusive end index of the range
+ */
+ public @FloatRange(from = 0.0) @Px float getWidth(
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end) {
+ Preconditions.checkArgument(0 <= start && start <= mChars.length,
+ "start(" + start + ") must be 0 <= start <= " + mChars.length);
+ Preconditions.checkArgument(0 <= end && end <= mChars.length,
+ "end(" + end + ") must be 0 <= end <= " + mChars.length);
+ Preconditions.checkArgument(start <= end,
+ "start(" + start + ") is larger than end(" + end + ")");
+ return nGetWidth(mNativePtr, start, end);
+ }
+
+ /**
+ * Returns a memory usage of the native object.
+ *
+ * @hide
+ */
+ public int getMemoryUsage() {
+ return nGetMemoryUsage(mNativePtr);
+ }
+
+ /**
+ * Retrieves the boundary box of the given range
+ *
+ * @param start an inclusive start index of the range
+ * @param end an exclusive end index of the range
+ * @param rect an output parameter
+ */
+ public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @NonNull Rect rect) {
+ Preconditions.checkArgument(0 <= start && start <= mChars.length,
+ "start(" + start + ") must be 0 <= start <= " + mChars.length);
+ Preconditions.checkArgument(0 <= end && end <= mChars.length,
+ "end(" + end + ") must be 0 <= end <= " + mChars.length);
+ Preconditions.checkArgument(start <= end,
+ "start(" + start + ") is larger than end(" + end + ")");
+ Preconditions.checkNotNull(rect);
+ nGetBounds(mNativePtr, mChars, start, end, rect);
+ }
+
+ /**
+ * Returns the width of the character at the given offset.
+ *
+ * @param offset an offset of the character.
+ */
+ public @FloatRange(from = 0.0f) @Px float getCharWidthAt(@IntRange(from = 0) int offset) {
+ Preconditions.checkArgument(0 <= offset && offset < mChars.length,
+ "offset(" + offset + ") is larger than text length: " + mChars.length);
+ return nGetCharWidthAt(mNativePtr, offset);
+ }
+
+ /**
+ * Returns a native pointer of the underlying native object.
+ *
+ * @hide
+ */
+ public long getNativePtr() {
+ return mNativePtr;
+ }
+
+ @CriticalNative
+ private static native float nGetWidth(/* Non Zero */ long nativePtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end);
+
+ @CriticalNative
+ private static native /* Non Zero */ long nGetReleaseFunc();
+
+ @CriticalNative
+ private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr);
+
+ private static native void nGetBounds(long nativePtr, char[] buf, int start, int end,
+ Rect rect);
+
+ @CriticalNative
+ private static native float nGetCharWidthAt(long nativePtr, int offset);
+
+ /**
+ * Helper class for creating a {@link MeasuredText}.
+ */
+ public static class Builder {
+ private long mNativePtr;
+
+ private final @NonNull char[] mText;
+ private boolean mComputeHyphenation = false;
+ private boolean mComputeLayout = true;
+
+ /**
+ * Construct a builder.
+ *
+ * The MeasuredText returned by build method will hold a reference of the text. Developer is
+ * not supposed to modify the text.
+ *
+ * @param text a text
+ */
+ public Builder(@NonNull char[] text) {
+ Preconditions.checkNotNull(text);
+ mText = text;
+ mNativePtr = nInitBuilder();
+ }
+
+ /**
+ * Apply styles to the given range.
+ *
+ * @param paint a paint
+ * @param start an inclusive start index of the range
+ * @param end an exclusive end index of the range
+ * @param isRtl true if the text is in RTL context, otherwise false.
+ */
+ public Builder addStyleRun(@NonNull Paint paint,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl) {
+ Preconditions.checkNotNull(paint);
+ nAddStyleRun(mNativePtr, paint.getNativeInstance(), start, end, isRtl);
+ return this;
+ }
+
+ /**
+ * Used to inform the text layout that the given range is replaced with the object of given
+ * width.
+ *
+ * Informs the layout engine that the given range should not be processed, instead the
+ * provided width should be used for calculating the width of that range.
+ *
+ * @param start an inclusive start index of the range
+ * @param end an exclusive end index of the range
+ * @param width a replacement width of the range
+ */
+ public Builder addReplacementRun(@NonNull Paint paint,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @FloatRange(from = 0) float width) {
+ nAddReplacementRun(mNativePtr, paint.getNativeInstance(), start, end, width);
+ return this;
+ }
+
+ /**
+ * By passing true to this method, the build method will compute all possible hyphenation
+ * pieces as well.
+ *
+ * If you don't want to use automatic hyphenation, you can pass false to this method and
+ * save the computation time of hyphenation. The default value is false.
+ *
+ * Even if you pass false to this method, you can still enable automatic hyphenation of
+ * LineBreaker but line break computation becomes slower.
+ *
+ * @param computeHyphenation true if you want to use automatic hyphenations.
+ */
+ public Builder setComputeHyphenation(boolean computeHyphenation) {
+ mComputeHyphenation = computeHyphenation;
+ return this;
+ }
+
+ /**
+ * By passing true to this method, the build method will compute all full layout
+ * information.
+ *
+ * If you don't use {@link MeasuredText#getBounds(int,int,android.graphics.Rect)}, you can
+ * pass false to this method and save the memory spaces. The default value is true.
+ *
+ * Even if you pass false to this method, you can still call getBounds but it becomes
+ * slower.
+ *
+ * @param computeLayout true if you want to retrieve full layout info, e.g. bbox.
+ */
+ public Builder setComputeLayout(boolean computeLayout) {
+ mComputeLayout = computeLayout;
+ return this;
+ }
+
+ /**
+ * Creates a MeasuredText.
+ *
+ * Once you called build() method, you can't reuse the Builder class again.
+ * @throws IllegalStateException if this Builder is reused.
+ */
+ public MeasuredText build() {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("Builder can not be reused.");
+ }
+ try {
+ long ptr = nBuildMeasuredText(mNativePtr, mText, mComputeHyphenation,
+ mComputeLayout);
+ MeasuredText res = new MeasuredText(ptr, mText);
+ sRegistry.registerNativeAllocation(res, ptr);
+ return res;
+ } finally {
+ nFreeBuilder(mNativePtr);
+ mNativePtr = 0;
+ }
+ }
+
+ private static native /* Non Zero */ long nInitBuilder();
+
+ /**
+ * Apply style to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param isRtl True if the text is RTL.
+ */
+ private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ boolean isRtl);
+ /**
+ * Apply ReplacementRun to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param width The width of the replacement.
+ */
+ private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @FloatRange(from = 0) float width);
+
+ private static native long nBuildMeasuredText(
+ /* Non Zero */ long nativeBuilderPtr,
+ @NonNull char[] text,
+ boolean computeHyphenation,
+ boolean computeLayout);
+
+ private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
+ }
+}
diff --git a/keystore/OWNERS b/keystore/OWNERS
new file mode 100644
index 000000000000..a63ca46df2a6
--- /dev/null
+++ b/keystore/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+robbarnes@google.com
+swillden@google.com
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 74cab920cf2d..98af3eb05391 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -50,6 +50,7 @@ cc_library {
"LocaleData.cpp",
"misc.cpp",
"ObbFile.cpp",
+ "PosixUtils.cpp",
"ResourceTypes.cpp",
"ResourceUtils.cpp",
"StreamingZipInflater.cpp",
@@ -157,6 +158,7 @@ cc_test {
srcs: [
"tests/BackupData_test.cpp",
"tests/ObbFile_test.cpp",
+ "tests/PosixUtils_test.cpp",
],
shared_libs: common_test_libs + ["libui"],
},
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 8f58f74d4652..66a547723b2f 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -39,7 +39,7 @@ using base::unique_fd;
static const std::string kResourcesArsc("resources.arsc");
-ApkAssets::ApkAssets(void* unmanaged_handle, const std::string& path)
+ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path)
: zip_handle_(unmanaged_handle, ::CloseArchive), path_(path) {
}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9c1629bc36f5..04cc5bb30ade 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -67,10 +67,10 @@ AssetManager2::AssetManager2() {
}
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
- bool invalidate_caches) {
+ bool invalidate_caches, bool filter_incompatible_configs) {
apk_assets_ = apk_assets;
BuildDynamicRefTable();
- RebuildFilterList();
+ RebuildFilterList(filter_incompatible_configs);
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
@@ -825,7 +825,7 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
return 0u;
}
-void AssetManager2::RebuildFilterList() {
+void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
for (PackageGroup& group : package_groups_) {
for (ConfiguredPackage& impl : group.packages_) {
// Destroy it.
@@ -841,7 +841,7 @@ void AssetManager2::RebuildFilterList() {
for (auto iter = spec->types; iter != iter_end; ++iter) {
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
- if (this_config.match(configuration_)) {
+ if (!filter_incompatible_configs || this_config.match(configuration_)) {
group.configurations.push_back(this_config);
group.types.push_back(*iter);
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c2740c9fbaa4..68d216d286cf 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -203,6 +203,39 @@ static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset
return true;
}
+LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
+ : loadedPackage_(lp),
+ typeIndex_(ti),
+ entryIndex_(ei),
+ typeIndexEnd_(lp->resource_ids_.size() + 1) {
+ while (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] == 0) {
+ typeIndex_++;
+ }
+}
+
+LoadedPackage::iterator& LoadedPackage::iterator::operator++() {
+ while (typeIndex_ < typeIndexEnd_) {
+ if (entryIndex_ + 1 < loadedPackage_->resource_ids_[typeIndex_]) {
+ entryIndex_++;
+ break;
+ }
+ entryIndex_ = 0;
+ typeIndex_++;
+ if (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] != 0) {
+ break;
+ }
+ }
+ return *this;
+}
+
+uint32_t LoadedPackage::iterator::operator*() const {
+ if (typeIndex_ >= typeIndexEnd_) {
+ return 0;
+ }
+ return make_resid(loadedPackage_->package_id_, typeIndex_ + loadedPackage_->type_id_offset_,
+ entryIndex_);
+}
+
const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
uint16_t entry_index) {
uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
@@ -488,6 +521,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
if (builder_ptr == nullptr) {
builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+ loaded_package->resource_ids_.set(type_spec->id, entry_count);
} else {
LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
type_spec->id);
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
new file mode 100644
index 000000000000..df0dd7ce463d
--- /dev/null
+++ b/libs/androidfw/PosixUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+// nothing to see here
+#else
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "android-base/logging.h"
+
+#include "androidfw/PosixUtils.h"
+
+namespace {
+
+std::unique_ptr<std::string> ReadFile(int fd) {
+ std::unique_ptr<std::string> str(new std::string());
+ char buf[1024];
+ ssize_t r;
+ while ((r = read(fd, buf, sizeof(buf))) > 0) {
+ str->append(buf, r);
+ }
+ if (r != 0) {
+ return nullptr;
+ }
+ return str;
+}
+
+}
+
+namespace android {
+namespace util {
+
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) {
+ int stdout[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stdout) != 0) {
+ PLOG(ERROR) << "pipe";
+ return nullptr;
+ }
+
+ int stderr[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stderr) != 0) {
+ PLOG(ERROR) << "pipe";
+ close(stdout[0]);
+ close(stdout[1]);
+ return nullptr;
+ }
+
+ char const** argv0 = (char const**)malloc(sizeof(char*) * (argv.size() + 1));
+ for (size_t i = 0; i < argv.size(); i++) {
+ argv0[i] = argv[i].c_str();
+ }
+ argv0[argv.size()] = nullptr;
+ switch (fork()) {
+ case -1: // error
+ free(argv0);
+ PLOG(ERROR) << "fork";
+ return nullptr;
+ case 0: // child
+ close(stdout[0]);
+ if (dup2(stdout[1], STDOUT_FILENO) == -1) {
+ abort();
+ }
+ close(stderr[0]);
+ if (dup2(stderr[1], STDERR_FILENO) == -1) {
+ abort();
+ }
+ execvp(argv0[0], const_cast<char* const*>(argv0));
+ PLOG(ERROR) << "execv";
+ abort();
+ default: // parent
+ free(argv0);
+ close(stdout[1]);
+ close(stderr[1]);
+ int status;
+ wait(&status);
+ if (!WIFEXITED(status)) {
+ return nullptr;
+ }
+ std::unique_ptr<ProcResult> result(new ProcResult());
+ result->status = status;
+ const auto out = ReadFile(stdout[0]);
+ result->stdout = out ? *out : "";
+ close(stdout[0]);
+ const auto err = ReadFile(stderr[0]);
+ result->stderr = err ? *err : "";
+ close(stderr[0]);
+ return result;
+ }
+}
+
+} // namespace util
+} // namespace android
+#endif
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 69702e314442..db2d0382bcf6 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -27,6 +27,9 @@
#include "androidfw/LoadedArsc.h"
#include "androidfw/misc.h"
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
+
namespace android {
class LoadedIdmap;
@@ -88,9 +91,9 @@ class ApkAssets {
// Creates an Asset from any file on the file system.
static std::unique_ptr<Asset> CreateAssetFromFile(const std::string& path);
- ApkAssets(void* unmanaged_handle, const std::string& path);
+ ApkAssets(ZipArchiveHandle unmanaged_handle, const std::string& path);
- using ZipArchivePtr = std::unique_ptr<void, void(*)(void*)>;
+ using ZipArchivePtr = std::unique_ptr<ZipArchive, void(*)(ZipArchiveHandle)>;
ZipArchivePtr zip_handle_;
const std::string path_;
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ad31f6940438..2f0ee01639fe 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -96,7 +96,12 @@ class AssetManager2 {
// Only pass invalidate_caches=false when it is known that the structure
// change in ApkAssets is due to a safe addition of resources with completely
// new resource IDs.
- bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+ //
+ // Only pass in filter_incompatible_configs=false when you want to load all
+ // configurations (including incompatible ones) such as when constructing an
+ // idmap.
+ bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true,
+ bool filter_incompatible_configs = true);
inline const std::vector<const ApkAssets*> GetApkAssets() const {
return apk_assets_;
@@ -274,7 +279,7 @@ class AssetManager2 {
// Triggers the re-construction of lists of types that match the set configuration.
// This should always be called when mutating the AssetManager's configuration or ApkAssets set.
- void RebuildFilterList();
+ void RebuildFilterList(bool filter_incompatible_configs = true);
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fcd9e7b..349b379778a6 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,55 @@ using TypeSpecPtr = util::unique_cptr<TypeSpec>;
class LoadedPackage {
public:
+ class iterator {
+ public:
+ iterator& operator=(const iterator& rhs) {
+ loadedPackage_ = rhs.loadedPackage_;
+ typeIndex_ = rhs.typeIndex_;
+ entryIndex_ = rhs.entryIndex_;
+ return *this;
+ }
+
+ bool operator==(const iterator& rhs) const {
+ return loadedPackage_ == rhs.loadedPackage_ &&
+ typeIndex_ == rhs.typeIndex_ &&
+ entryIndex_ == rhs.entryIndex_;
+ }
+
+ bool operator!=(const iterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ iterator operator++(int) {
+ size_t prevTypeIndex_ = typeIndex_;
+ size_t prevEntryIndex_ = entryIndex_;
+ operator++();
+ return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
+ }
+
+ iterator& operator++();
+
+ uint32_t operator*() const;
+
+ private:
+ friend class LoadedPackage;
+
+ iterator(const LoadedPackage* lp, size_t ti, size_t ei);
+
+ const LoadedPackage* loadedPackage_;
+ size_t typeIndex_;
+ size_t entryIndex_;
+ const size_t typeIndexEnd_; // STL style end, so one past the last element
+ };
+
+ iterator begin() const {
+ return iterator(this, 0, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, resource_ids_.size() + 1, 0);
+ }
+
static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
const LoadedIdmap* loaded_idmap, bool system,
bool load_as_shared_library);
@@ -182,6 +231,7 @@ class LoadedPackage {
bool overlay_ = false;
ByteBucketArray<TypeSpecPtr> type_specs_;
+ ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
};
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
new file mode 100644
index 000000000000..8fc3ee2733c7
--- /dev/null
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace util {
+
+struct ProcResult {
+ int status;
+ std::string stdout;
+ std::string stderr;
+};
+
+// Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
+// otherwise a ProcResult containing the external process' exit status and captured stdout and
+// stderr.
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv);
+
+} // namespace util
+} // namespace android
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 03154d04def1..c221e3b7aeae 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -41,7 +41,8 @@
#include <unistd.h>
#include <time.h>
-typedef void* ZipArchiveHandle;
+struct ZipArchive;
+typedef ZipArchive* ZipArchiveHandle;
namespace android {
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index cae632ddea30..ffa48367c252 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -278,4 +278,52 @@ TEST(LoadedArscTest, LoadOverlay) {
// sizeof(Res_value) might not be backwards compatible.
TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+TEST(LoadedArscTest, ResourceIdentifierIterator) {
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+
+ const auto& loaded_package = packages[0];
+ auto iter = loaded_package->begin();
+ auto end = loaded_package->end();
+
+ ASSERT_NE(end, iter);
+ ASSERT_EQ(0x7f010000u, *iter++);
+ ASSERT_EQ(0x7f010001u, *iter++);
+ ASSERT_EQ(0x7f020000u, *iter++);
+ ASSERT_EQ(0x7f020001u, *iter++);
+ ASSERT_EQ(0x7f030000u, *iter++);
+ ASSERT_EQ(0x7f030001u, *iter++);
+ ASSERT_EQ(0x7f030002u, *iter++); // note: string without default, excluded by aapt2 dump
+ ASSERT_EQ(0x7f040000u, *iter++);
+ ASSERT_EQ(0x7f040001u, *iter++);
+ ASSERT_EQ(0x7f040002u, *iter++);
+ ASSERT_EQ(0x7f040003u, *iter++);
+ ASSERT_EQ(0x7f040004u, *iter++);
+ ASSERT_EQ(0x7f040005u, *iter++);
+ ASSERT_EQ(0x7f040006u, *iter++);
+ ASSERT_EQ(0x7f040007u, *iter++);
+ ASSERT_EQ(0x7f040008u, *iter++);
+ ASSERT_EQ(0x7f040009u, *iter++);
+ ASSERT_EQ(0x7f04000au, *iter++);
+ ASSERT_EQ(0x7f04000bu, *iter++);
+ ASSERT_EQ(0x7f04000cu, *iter++);
+ ASSERT_EQ(0x7f04000du, *iter++);
+ ASSERT_EQ(0x7f050000u, *iter++);
+ ASSERT_EQ(0x7f050001u, *iter++);
+ ASSERT_EQ(0x7f060000u, *iter++);
+ ASSERT_EQ(0x7f070000u, *iter++);
+ ASSERT_EQ(0x7f070001u, *iter++);
+ ASSERT_EQ(0x7f070002u, *iter++);
+ ASSERT_EQ(0x7f070003u, *iter++);
+ ASSERT_EQ(end, iter);
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
new file mode 100644
index 000000000000..cf97f87a4163
--- /dev/null
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 <utility>
+
+#include "androidfw/PosixUtils.h"
+
+#include "TestHelpers.h"
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+namespace android {
+namespace util {
+
+TEST(PosixUtilsTest, AbsolutePathToBinary) {
+ const auto result = ExecuteBinary({"/bin/date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, RelativePathToBinary) {
+ const auto result = ExecuteBinary({"date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, BadParameters) {
+ const auto result = ExecuteBinary({"/bin/date", "--this-parameter-is-not-supported"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_NE(result->status, 0);
+}
+
+TEST(PosixUtilsTest, NoSuchBinary) {
+ const auto result = ExecuteBinary({"/this/binary/does/not/exist"});
+ ASSERT_THAT(result, IsNull());
+}
+
+} // android
+} // util
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 494e5135d5bb..e3ec45b20883 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -61,6 +61,7 @@ cc_defaults {
shared_libs: [
"liblog",
"libcutils",
+ "libstatslog",
"libutils",
"libEGL",
"libGLESv2",
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index f2d50cd42523..e7ae7675f0b8 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -18,6 +18,7 @@
#include <errno.h>
#include <inttypes.h>
+#include <statslog.h>
#include <sys/mman.h>
#include <algorithm>
@@ -181,6 +182,7 @@ void JankTracker::finishFrame(const FrameInfo& frame) {
ALOGI("%s", ss.str().c_str());
// Just so we have something that counts up, the value is largely irrelevant
ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
+ android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration));
}
}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 9c284531674f..b04194f378bc 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -134,14 +134,15 @@ sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef)
}
sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
- PixelFormat format = graphicBuffer->getPixelFormat();
- if (!graphicBuffer.get() ||
- (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
- return nullptr;
- }
+ return createFrom(graphicBuffer, SkColorSpace::MakeSRGB());
+}
+
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace) {
+ // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
+ // view the colorspace as RGBA8888.
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
+ colorSpace);
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 43d457a77b15..238c764cdea6 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -64,6 +64,8 @@ public:
size_t rowBytes);
static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
+ static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
+ sk_sp<SkColorSpace> colorSpace);
static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 6594bd22c0b1..d746978b0a61 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -16,6 +16,8 @@
#pragma once
+#include "SkiaUtils.h"
+
#include <SkCanvas.h>
#include <SkDrawable.h>
#include <SkMatrix.h>
@@ -89,7 +91,7 @@ protected:
virtual SkRect onGetBounds() override {
// We don't want to enable a record time quick reject because the properties
// of the RenderNode may be updated on subsequent frames.
- return SkRect::MakeLargest();
+ return SkRectMakeLargest();
}
/**
* This function draws into a canvas as forceDraw, but does nothing if the render node has a
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 3c48d3604864..26cfa908228c 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -17,6 +17,7 @@
#pragma once
#include "RenderNodeDrawable.h"
+#include "SkiaUtils.h"
#include <SkCanvas.h>
#include <SkDrawable.h>
@@ -41,7 +42,7 @@ public:
explicit StartReorderBarrierDrawable(SkiaDisplayList* data);
protected:
- virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+ virtual SkRect onGetBounds() override { return SkRectMakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
private:
@@ -65,7 +66,7 @@ public:
explicit EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier);
protected:
- virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+ virtual SkRect onGetBounds() override { return SkRectMakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
private:
diff --git a/libs/hwui/pipeline/skia/SkiaUtils.h b/libs/hwui/pipeline/skia/SkiaUtils.h
new file mode 100644
index 000000000000..834446905216
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaUtils.h
@@ -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.
+ */
+
+#pragma once
+
+#include <SkRect.h>
+
+namespace android {
+
+static inline SkRect SkRectMakeLargest() {
+ const SkScalar v = SK_ScalarMax;
+ return { -v, -v, v, v };
+};
+
+} /* namespace android */
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index bc742b0c5a63..df5f45618070 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -35,23 +35,6 @@ SkBitmap createSkBitmap(int width, int height) {
return bitmap;
}
-/**
- * 1x1 bitmaps must not be optimized into solid color shaders, since HWUI can't
- * compose/render color shaders
- */
-TEST(SkiaBehavior, CreateBitmapShader1x1) {
- SkBitmap origBitmap = createSkBitmap(1, 1);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(origBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> s =
- image->makeShader(SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, nullptr);
-
- SkBitmap bitmap;
- SkShader::TileMode xy[2];
- ASSERT_TRUE(s->isABitmap(&bitmap, nullptr, xy))
- << "1x1 bitmap shader must query as bitmap shader";
- EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
-}
-
TEST(SkiaBehavior, genIds) {
SkBitmap bitmap = createSkBitmap(100, 100);
uint32_t genId = bitmap.getGenerationID();
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index cdf31da37074..65b4e26ab62f 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -24,6 +24,7 @@
#include "DamageAccumulator.h"
#include "IContextFactory.h"
#include "SkiaCanvas.h"
+#include "pipeline/skia/SkiaUtils.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
@@ -41,7 +42,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
});
LayerUpdateQueue layerUpdateQueue;
- SkRect dirty = SkRect::MakeLargest();
+ SkRect dirty = SkRectMakeLargest();
std::vector<sp<RenderNode>> renderNodes;
renderNodes.push_back(redNode);
bool opaque = true;
@@ -62,7 +63,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
});
LayerUpdateQueue layerUpdateQueue;
- SkRect dirty = SkRect::MakeLargest();
+ SkRect dirty = SkRectMakeLargest();
std::vector<sp<RenderNode>> renderNodes;
renderNodes.push_back(redNode);
bool opaque = true;
@@ -97,7 +98,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
});
LayerUpdateQueue layerUpdateQueue;
- SkRect dirty = SkRect::MakeLargest();
+ SkRect dirty = SkRectMakeLargest();
std::vector<sp<RenderNode>> renderNodes;
renderNodes.push_back(halfGreenNode);
android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
@@ -160,7 +161,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
// attach both layers to the update queue
LayerUpdateQueue layerUpdateQueue;
- SkRect dirty = SkRect::MakeLargest();
+ SkRect dirty = SkRectMakeLargest();
layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1));
ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6d10c2d692b1..b1968babe99f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2380,10 +2380,12 @@ public class LocationManager {
}
/**
+ * Return the package that implements the {@link #NETWORK_PROVIDER} functionality.
+ *
* @hide
*/
@SystemApi
- public String getNetworkProviderPackage() {
+ public @Nullable String getNetworkProviderPackage() {
try {
return mService.getNetworkProviderPackage();
} catch (RemoteException e) {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 2395b24f7136..b96a5853b9dc 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3252,7 +3252,7 @@ public class ExifInterface {
int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
// The following code limits the size of thumbnail size not to overflow EXIF data area.
- thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
+ thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
|| mMimeType == IMAGE_TYPE_RW2) {
thumbnailOffset += mExifOffset;
@@ -3981,6 +3981,10 @@ public class ExifInterface {
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
+
+ public int getLength() {
+ return mLength;
+ }
}
// An output stream to write EXIF data area, which can be written in either little or big endian
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
index 474d8b9ef03c..889a5f7efbb2 100644
--- a/media/java/android/media/MediaCrypto.java
+++ b/media/java/android/media/MediaCrypto.java
@@ -56,13 +56,15 @@ public final class MediaCrypto {
private static final native boolean isCryptoSchemeSupportedNative(@NonNull byte[] uuid);
/**
- * Instantiate a MediaCrypto object using opaque, crypto scheme specific
- * data.
+ * Instantiate a MediaCrypto object and associate it with a MediaDrm session
+ *
* @param uuid The UUID of the crypto scheme.
- * @param initData Opaque initialization data specific to the crypto scheme.
+ * @param sessionId The MediaDrm sessionId to associate with this
+ * MediaCrypto session. The sessionId may be changed after the MediaCrypto
+ * is created using {@link #setMediaDrmSession}
*/
- public MediaCrypto(@NonNull UUID uuid, @NonNull byte[] initData) throws MediaCryptoException {
- native_setup(getByteArrayFromUUID(uuid), initData);
+ public MediaCrypto(@NonNull UUID uuid, @NonNull byte[] sessionId) throws MediaCryptoException {
+ native_setup(getByteArrayFromUUID(uuid), sessionId);
}
/**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 850be786cce1..6d122d77a999 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1202,7 +1202,6 @@ public final class MediaDrm implements AutoCloseable {
* The maximum security level supported by the device. This is the default
* security level when a session is opened.
*/
- @SecurityLevel
public static final int getMaxSecurityLevel() {
return SECURITY_LEVEL_MAX;
}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 8665f283ffb2..db6da8c590c3 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -32,9 +32,6 @@ import android.view.SurfaceHolder;
import dalvik.system.CloseGuard;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -232,8 +229,7 @@ import java.util.concurrent.Executor;
* successful transition. Any other value will be an error. Call {@link #getState()} to
* determine the current state. </p>
*/
-public abstract class MediaPlayer2 implements SubtitleController.Listener
- , AutoCloseable
+public abstract class MediaPlayer2 implements AutoCloseable
, AudioRouting {
private final CloseGuard mGuard = CloseGuard.get();
@@ -242,8 +238,8 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
*
* @return A MediaPlayer2 object created
*/
- public static final MediaPlayer2 create() {
- return new MediaPlayer2Impl();
+ public static final MediaPlayer2 create(Context context) {
+ return new MediaPlayer2Impl(context);
}
private static final String[] decodeMediaPlayer2Uri(String location) {
@@ -1081,16 +1077,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
public abstract void reset();
/**
- * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
- * notified when the presentation time reaches (becomes greater than or equal to)
- * the value specified.
- *
- * @param mediaTimeUs presentation time to get timed event callback at
- * @hide
- */
- public void notifyAt(long mediaTimeUs) { }
-
- /**
* Checks whether the MediaPlayer2 is looping or non-looping.
*
* @return true if the MediaPlayer2 is currently looping, false otherwise
@@ -1237,95 +1223,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
*/
public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
- /** @hide */
- public void setSubtitleAnchor(
- SubtitleController controller,
- SubtitleController.Anchor anchor) { }
-
- /** @hide */
- @Override
- public void onSubtitleTrackSelected(SubtitleTrack track) { }
-
- /** @hide */
- public void addSubtitleSource(InputStream is, MediaFormat format) { }
-
- /* TODO: Limit the total number of external timed text source to a reasonable number.
- */
- /**
- * Adds an external timed text source file.
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param path The file path of external timed text source file.
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(String path, String mimeType) throws IOException { }
-
- /**
- * Adds an external timed text source file (Uri).
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param context the Context to use when resolving the Uri
- * @param uri the Content URI of the data you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(Context context, Uri uri, String mimeType) throws IOException { }
-
- /**
- * Adds an external timed text source file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public void addTimedTextSource(FileDescriptor fd, String mimeType) { }
-
- /**
- * Adds an external timed text file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param offset the offset into the file where the data to be played starts, in bytes
- * @param length the length in bytes of the data to be played
- * @param mime The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- public abstract void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime);
-
/**
* Returns the index of the audio, video, or subtitle track currently selected for playback,
* The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -1393,11 +1290,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
// This is an asynchronous call.
public abstract void deselectTrack(int index);
- /** @hide */
- public MediaTimeProvider getMediaTimeProvider() {
- return null;
- }
-
/**
* Interface definition for callbacks to be invoked when the player has the corresponding
* events.
@@ -1679,12 +1571,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
*/
public static final int MEDIA_INFO_METADATA_UPDATE = 802;
- /** A new set of external-only metadata is available. Used by
- * JAVA framework to avoid triggering track scanning.
- * @hide
- */
- public static final int MEDIA_INFO_EXTERNAL_METADATA_UPDATE = 803;
-
/** Informs that audio is not playing. Note that playback of the video
* is not interrupted.
* @see EventCallback#onInfo
@@ -1733,7 +1619,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener
MEDIA_INFO_BAD_INTERLEAVING,
MEDIA_INFO_NOT_SEEKABLE,
MEDIA_INFO_METADATA_UPDATE,
- MEDIA_INFO_EXTERNAL_METADATA_UPDATE,
MEDIA_INFO_AUDIO_NOT_PLAYING,
MEDIA_INFO_VIDEO_NOT_PLAYING,
MEDIA_INFO_TIMED_TEXT_ERROR,
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 678cb9af378d..084b2049e30b 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -19,7 +19,6 @@ package android.media;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -29,8 +28,6 @@ import android.graphics.Rect;
import android.media.MediaPlayer2Proto;
import android.media.MediaPlayer2Proto.PlayerMessage;
import android.media.MediaPlayer2Proto.Value;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleTrack.RenderingWidget;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -38,23 +35,17 @@ import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
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.view.Surface;
import android.view.SurfaceHolder;
-import android.widget.VideoView;
import com.android.framework.protobuf.InvalidProtocolBufferException;
import com.android.internal.annotations.GuardedBy;
-import libcore.io.IoBridge;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -69,15 +60,12 @@ import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Scanner;
import java.util.UUID;
-import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -93,6 +81,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private final static String TAG = "MediaPlayer2Impl";
+ private Context mContext;
+
private long mNativeContext; // accessed by native methods
private long mNativeSurfaceTexture; // accessed by native methods
private int mListenerContext; // accessed by native methods
@@ -149,15 +139,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
* to free the resources. If not released, too many MediaPlayer2Impl instances may
* result in an exception.</p>
*/
- public MediaPlayer2Impl() {
+ public MediaPlayer2Impl(Context context) {
+ mContext = context;
mHandlerThread = new HandlerThread("MediaPlayer2TaskThread");
mHandlerThread.start();
Looper looper = mHandlerThread.getLooper();
mTaskHandler = new TaskHandler(this, looper);
- mTimeProvider = new TimeProvider(this);
- mOpenSubtitleSources = new Vector<InputStream>();
-
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
@@ -473,12 +461,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
void process() {
mVolume = volume;
- _setVolume(volume, volume);
+ _setVolume(volume);
}
});
}
- private native void _setVolume(float leftVolume, float rightVolume);
+ private native void _setVolume(float volume);
/**
* Returns the current volume of this player to this player.
@@ -1503,24 +1491,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public void reset() {
- mSelectedSubtitleTrackIndex = -1;
- synchronized(mOpenSubtitleSources) {
- for (final InputStream is: mOpenSubtitleSources) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- mOpenSubtitleSources.clear();
- }
- if (mSubtitleController != null) {
- mSubtitleController.reset();
- }
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
- }
-
synchronized (mEventCbLock) {
mEventCallbackRecords.clear();
}
@@ -1543,31 +1513,11 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mTaskHandler.removeCallbacksAndMessages(null);
}
- synchronized (mIndexTrackPairs) {
- mIndexTrackPairs.clear();
- mInbandTrackIndices.clear();
- };
-
resetDrmState();
}
private native void _reset();
- /**
- * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
- * notified when the presentation time reaches (becomes greater than or equal to)
- * the value specified.
- *
- * @param mediaTimeUs presentation time to get timed event callback at
- * @hide
- */
- @Override
- public void notifyAt(long mediaTimeUs) {
- _notifyAt(mediaTimeUs);
- }
-
- private native void _notifyAt(long mediaTimeUs);
-
// Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
/**
@@ -1781,16 +1731,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
};
- // We would like domain specific classes with more informative names than the `first` and `second`
- // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
- // we document the meanings of `first` and `second` here:
- //
- // Pair.first - inband track index; non-null iff representing an inband track.
- // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
- // an inband subtitle track or any out-of-band track (subtitle or timedtext).
- private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
- private BitSet mInbandTrackIndices = new BitSet();
-
/**
* Returns a List of track information.
*
@@ -1802,21 +1742,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public List<TrackInfo> getTrackInfo() {
TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
- // add out-of-band tracks
- synchronized (mIndexTrackPairs) {
- TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
- for (int i = 0; i < allTrackInfo.length; i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.first != null) {
- // inband track
- allTrackInfo[i] = trackInfo[p.first];
- } else {
- SubtitleTrack track = p.second;
- allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
- }
- }
- return Arrays.asList(allTrackInfo);
- }
+ return Arrays.asList(trackInfo);
}
private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
@@ -1849,419 +1775,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return false;
}
- private SubtitleController mSubtitleController;
-
- /** @hide */
- @Override
- public void setSubtitleAnchor(
- SubtitleController controller,
- SubtitleController.Anchor anchor) {
- // TODO: create SubtitleController in MediaPlayer2
- mSubtitleController = controller;
- mSubtitleController.setAnchor(anchor);
- }
-
- /**
- * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
- * necessary when clients don't provide their own SubtitleControllers using the public version
- * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
- */
- private synchronized void setSubtitleAnchor() {
- if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
- final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- Context context = ActivityThread.currentApplication();
- mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
- mSubtitleController.setAnchor(new Anchor() {
- @Override
- public void setSubtitleWidget(RenderingWidget subtitleWidget) {
- }
-
- @Override
- public Looper getSubtitleLooper() {
- return Looper.getMainLooper();
- }
- });
- thread.getLooper().quitSafely();
- }
- });
- try {
- thread.join();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- Log.w(TAG, "failed to join SetSubtitleAnchorThread");
- }
- }
- }
-
- private int mSelectedSubtitleTrackIndex = -1;
- private Vector<InputStream> mOpenSubtitleSources;
-
- private EventCallback mSubtitleDataCallback = new EventCallback() {
- @Override
- public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
- int index = data.getTrackIndex();
- synchronized (mIndexTrackPairs) {
- for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
- if (p.first != null && p.first == index && p.second != null) {
- // inband subtitle track that owns data
- SubtitleTrack track = p.second;
- track.onData(data);
- }
- }
- }
- }
- };
-
- /** @hide */
- @Override
- public void onSubtitleTrackSelected(SubtitleTrack track) {
- if (mSelectedSubtitleTrackIndex >= 0) {
- try {
- selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
- } catch (IllegalStateException e) {
- }
- mSelectedSubtitleTrackIndex = -1;
- }
- unregisterEventCallback(mSubtitleDataCallback);
- if (track == null) {
- return;
- }
-
- synchronized (mIndexTrackPairs) {
- for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
- if (p.first != null && p.second == track) {
- // inband subtitle track that is selected
- mSelectedSubtitleTrackIndex = p.first;
- break;
- }
- }
- }
-
- if (mSelectedSubtitleTrackIndex >= 0) {
- try {
- selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
- } catch (IllegalStateException e) {
- }
- final Executor executor = (runnable) -> mTaskHandler.post(runnable);
- registerEventCallback(executor, mSubtitleDataCallback);
- }
- // no need to select out-of-band tracks
- }
-
- /** @hide */
- @Override
- public void addSubtitleSource(InputStream is, MediaFormat format)
- throws IllegalStateException
- {
- final InputStream fIs = is;
- final MediaFormat fFormat = format;
-
- if (is != null) {
- // Ensure all input streams are closed. It is also a handy
- // way to implement timeouts in the future.
- synchronized(mOpenSubtitleSources) {
- mOpenSubtitleSources.add(is);
- }
- } else {
- Log.w(TAG, "addSubtitleSource called with null InputStream");
- }
-
- getMediaTimeProvider();
-
- // process each subtitle in its own thread
- final HandlerThread thread = new HandlerThread("SubtitleReadThread",
- Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- private int addTrack() {
- if (fIs == null || mSubtitleController == null) {
- return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
- }
-
- SubtitleTrack track = mSubtitleController.addTrack(fFormat);
- if (track == null) {
- return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
- }
-
- // TODO: do the conversion in the subtitle track
- Scanner scanner = new Scanner(fIs, "UTF-8");
- String contents = scanner.useDelimiter("\\A").next();
- synchronized(mOpenSubtitleSources) {
- mOpenSubtitleSources.remove(fIs);
- }
- scanner.close();
- 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);
- return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
- }
-
- public void run() {
- int res = addTrack();
- if (mTaskHandler != null) {
- Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
- mTaskHandler.sendMessage(m);
- }
- thread.getLooper().quitSafely();
- }
- });
- }
-
- private void scanInternalSubtitleTracks() {
- setSubtitleAnchor();
-
- populateInbandTracks();
-
- if (mSubtitleController != null) {
- mSubtitleController.selectDefaultTrack();
- }
- }
-
- private void populateInbandTracks() {
- TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < tracks.length; i++) {
- if (mInbandTrackIndices.get(i)) {
- continue;
- } else {
- mInbandTrackIndices.set(i);
- }
-
- // newly appeared inband track
- if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- SubtitleTrack track = mSubtitleController.addTrack(
- tracks[i].getFormat());
- mIndexTrackPairs.add(Pair.create(i, track));
- } else {
- mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
- }
- }
- }
- }
-
- /* TODO: Limit the total number of external timed text source to a reasonable number.
- */
- /**
- * Adds an external timed text source file.
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param path The file path of external timed text source file.
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(String path, String mimeType)
- throws IOException {
- if (!availableMimeTypeForExternalSource(mimeType)) {
- final String msg = "Illegal mimeType for timed text source: " + mimeType;
- throw new IllegalArgumentException(msg);
- }
-
- File file = new File(path);
- if (file.exists()) {
- FileInputStream is = new FileInputStream(file);
- FileDescriptor fd = is.getFD();
- addTimedTextSource(fd, mimeType);
- is.close();
- } else {
- // We do not support the case where the path is not a file.
- throw new IOException(path);
- }
- }
-
-
- /**
- * Adds an external timed text source file (Uri).
- *
- * Currently supported format is SubRip with the file extension .srt, case insensitive.
- * Note that a single external timed text source may contain multiple tracks in it.
- * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
- * additional tracks become available after this method call.
- *
- * @param context the Context to use when resolving the Uri
- * @param uri the Content URI of the data you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IOException if the file cannot be accessed or is corrupted.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(Context context, Uri uri, String mimeType)
- throws IOException {
- String scheme = uri.getScheme();
- if(scheme == null || scheme.equals("file")) {
- addTimedTextSource(uri.getPath(), mimeType);
- return;
- }
-
- AssetFileDescriptor fd = null;
- try {
- ContentResolver resolver = context.getContentResolver();
- fd = resolver.openAssetFileDescriptor(uri, "r");
- if (fd == null) {
- return;
- }
- addTimedTextSource(fd.getFileDescriptor(), mimeType);
- return;
- } catch (SecurityException ex) {
- } catch (IOException ex) {
- } finally {
- if (fd != null) {
- fd.close();
- }
- }
- }
-
- /**
- * Adds an external timed text source file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param mimeType The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(FileDescriptor fd, String mimeType) {
- // intentionally less than LONG_MAX
- addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
- }
-
- /**
- * Adds an external timed text file (FileDescriptor).
- *
- * It is the caller's responsibility to close the file descriptor.
- * It is safe to do so as soon as this call returns.
- *
- * Currently supported format is SubRip. Note that a single external timed text source may
- * contain multiple tracks in it. One can find the total number of available tracks
- * using {@link #getTrackInfo()} to see what additional tracks become available
- * after this method call.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @param offset the offset into the file where the data to be played starts, in bytes
- * @param length the length in bytes of the data to be played
- * @param mime The mime type of the file. Must be one of the mime types listed above.
- * @throws IllegalArgumentException if the mimeType is not supported.
- * @throws IllegalStateException if called in an invalid state.
- * @hide
- */
- @Override
- public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
- if (!availableMimeTypeForExternalSource(mime)) {
- throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
- }
-
- final FileDescriptor dupedFd;
- try {
- dupedFd = Os.dup(fd);
- } catch (ErrnoException ex) {
- Log.e(TAG, ex.getMessage(), ex);
- throw new RuntimeException(ex);
- }
-
- final MediaFormat fFormat = new MediaFormat();
- fFormat.setString(MediaFormat.KEY_MIME, mime);
- fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
-
- // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
- if (mSubtitleController == null) {
- setSubtitleAnchor();
- }
-
- if (!mSubtitleController.hasRendererFor(fFormat)) {
- // test and add not atomic
- Context context = ActivityThread.currentApplication();
- mSubtitleController.registerRenderer(new SRTRenderer(context, mTaskHandler));
- }
- final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
- synchronized (mIndexTrackPairs) {
- mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
- }
-
- getMediaTimeProvider();
-
- final long offset2 = offset;
- final long length2 = length;
- final HandlerThread thread = new HandlerThread(
- "TimedTextReadThread",
- Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
- thread.start();
- Handler handler = new Handler(thread.getLooper());
- handler.post(new Runnable() {
- private int addTrack() {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try {
- Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
- byte[] buffer = new byte[4096];
- for (long total = 0; total < length2;) {
- int bytesToRead = (int) Math.min(buffer.length, length2 - total);
- int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
- if (bytes < 0) {
- break;
- } else {
- bos.write(buffer, 0, bytes);
- 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);
- return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
- } catch (Exception e) {
- Log.e(TAG, e.getMessage(), e);
- return MEDIA_INFO_TIMED_TEXT_ERROR;
- } finally {
- try {
- Os.close(dupedFd);
- } catch (ErrnoException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- }
- }
-
- public void run() {
- int res = addTrack();
- if (mTaskHandler != null) {
- Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
- mTaskHandler.sendMessage(m);
- }
- thread.getLooper().quitSafely();
- }
- });
- }
-
/**
* Returns the index of the audio, video, or subtitle track currently selected for playback,
* The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -2281,22 +1794,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public int getSelectedTrack(int trackType) {
- if (mSubtitleController != null
- && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
- || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
- SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
- if (subtitleTrack != null) {
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < mIndexTrackPairs.size(); i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
- return i;
- }
- }
- }
- }
- }
-
PlayerMessage request = PlayerMessage.newBuilder()
.addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
.addValues(Value.newBuilder().setInt32Value(trackType))
@@ -2305,16 +1802,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if (response == null) {
return -1;
}
- int inbandTrackIndex = response.getValues(0).getInt32Value();
- synchronized (mIndexTrackPairs) {
- for (int i = 0; i < mIndexTrackPairs.size(); i++) {
- Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
- if (p.first != null && p.first == inbandTrackIndex) {
- return i;
- }
- }
- }
- return -1;
+ return response.getValues(0).getInt32Value();
}
/**
@@ -2381,56 +1869,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private void selectOrDeselectTrack(int index, boolean select)
throws IllegalStateException {
- // handle subtitle track through subtitle controller
- populateInbandTracks();
-
- Pair<Integer,SubtitleTrack> p = null;
- try {
- p = mIndexTrackPairs.get(index);
- } catch (ArrayIndexOutOfBoundsException e) {
- // ignore bad index
- return;
- }
-
- SubtitleTrack track = p.second;
- if (track == null) {
- // inband (de)select
- selectOrDeselectInbandTrack(p.first, select);
- return;
- }
-
- if (mSubtitleController == null) {
- return;
- }
-
- if (!select) {
- // out-of-band deselect
- if (mSubtitleController.getSelectedTrack() == track) {
- mSubtitleController.selectTrack(null);
- } else {
- Log.w(TAG, "trying to deselect track that was not selected");
- }
- return;
- }
-
- // out-of-band select
- if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
- int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
- synchronized (mIndexTrackPairs) {
- if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
- Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
- if (p2.first != null && p2.second == null) {
- // deselect inband counterpart
- selectOrDeselectInbandTrack(p2.first, false);
- }
- }
- }
- }
- mSubtitleController.selectTrack(track);
- }
-
- private void selectOrDeselectInbandTrack(int index, boolean select)
- throws IllegalStateException {
PlayerMessage request = PlayerMessage.newBuilder()
.addValues(Value.newBuilder().setInt32Value(
select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK))
@@ -2460,10 +1898,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
mHandlerThread.quitSafely();
mHandlerThread = null;
}
- if (mTimeProvider != null) {
- mTimeProvider.close();
- mTimeProvider = null;
- }
// Modular DRM clean up
mOnDrmConfigHelper = null;
@@ -2500,17 +1934,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private static final int MEDIA_DRM_INFO = 210;
private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
- private TimeProvider mTimeProvider;
-
- /** @hide */
- @Override
- public MediaTimeProvider getMediaTimeProvider() {
- if (mTimeProvider == null) {
- mTimeProvider = new TimeProvider(this);
- }
- return mTimeProvider;
- }
-
private class TaskHandler extends Handler {
private MediaPlayer2Impl mMediaPlayer;
@@ -2550,17 +1973,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
switch(msg.what) {
case MEDIA_PREPARED:
{
- try {
- scanInternalSubtitleTracks();
- } catch (RuntimeException e) {
- // send error message instead of crashing;
- // send error message instead of inlining a call to onError
- // to avoid code duplication.
- Message msg2 = obtainMessage(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
- sendMessage(msg2);
- }
-
if (dsd != null) {
sendEvent(new EventNotifier() {
@Override
@@ -2656,21 +2068,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
case MEDIA_STOPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onStopped();
- }
- break;
- }
-
case MEDIA_STARTED:
case MEDIA_PAUSED:
+ case MEDIA_SKIPPED:
+ case MEDIA_NOTIFY_TIME:
{
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onPaused(msg.what == MEDIA_PAUSED);
- }
+ // Do nothing. The client should have enough information with
+ // {@link EventCallback#onMediaTimeDiscontinuity}.
break;
}
@@ -2706,15 +2110,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
processPendingTask_l();
}
}
- }
- // fall through
-
- case MEDIA_SKIPPED:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onSeekComplete(mMediaPlayer);
- }
return;
}
@@ -2759,33 +2154,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
break;
-
- case MEDIA_INFO_METADATA_UPDATE:
- try {
- scanInternalSubtitleTracks();
- } catch (RuntimeException e) {
- Message msg2 = obtainMessage(
- MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
- null);
- sendMessage(msg2);
- }
- // fall through
-
- case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
- msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
- // update default track selection
- if (mSubtitleController != null) {
- mSubtitleController.selectDefaultTrack();
- }
- break;
-
- case MEDIA_INFO_BUFFERING_START:
- case MEDIA_INFO_BUFFERING_END:
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
- }
- break;
}
sendEvent(new EventNotifier() {
@@ -2806,15 +2174,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
return;
}
- case MEDIA_NOTIFY_TIME:
- {
- TimeProvider timeProvider = mTimeProvider;
- if (timeProvider != null) {
- timeProvider.onNotifyTime();
- }
- return;
- }
-
case MEDIA_TIMED_TEXT:
{
final TimedText text;
@@ -4241,396 +3600,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
}
}
- /** @hide */
- static class TimeProvider implements MediaTimeProvider {
- private static final String TAG = "MTP";
- private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
- private static final long MAX_EARLY_CALLBACK_US = 1000;
- private static final long TIME_ADJUSTMENT_RATE = 2; /* meaning 1/2 */
- private long mLastTimeUs = 0;
- private MediaPlayer2Impl mPlayer;
- private boolean mPaused = true;
- private boolean mStopped = true;
- private boolean mBuffering;
- private long mLastReportedTime;
- // since we are expecting only a handful listeners per stream, there is
- // no need for log(N) search performance
- private MediaTimeProvider.OnMediaTimeListener mListeners[];
- private long mTimes[];
- private EventHandler mEventHandler;
- private boolean mRefresh = false;
- private boolean mPausing = false;
- private boolean mSeeking = false;
- private static final int NOTIFY = 1;
- private static final int NOTIFY_TIME = 0;
- private static final int NOTIFY_STOP = 2;
- private static final int NOTIFY_SEEK = 3;
- private static final int NOTIFY_TRACK_DATA = 4;
- private HandlerThread mHandlerThread;
-
- /** @hide */
- public boolean DEBUG = false;
-
- public TimeProvider(MediaPlayer2Impl mp) {
- mPlayer = mp;
- try {
- getCurrentTimeUs(true, false);
- } catch (IllegalStateException e) {
- // we assume starting position
- mRefresh = true;
- }
-
- Looper looper;
- if ((looper = Looper.myLooper()) == null &&
- (looper = Looper.getMainLooper()) == null) {
- // Create our own looper here in case MP was created without one
- mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
- Process.THREAD_PRIORITY_FOREGROUND);
- mHandlerThread.start();
- looper = mHandlerThread.getLooper();
- }
- mEventHandler = new EventHandler(looper);
-
- mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
- mTimes = new long[0];
- mLastTimeUs = 0;
- }
-
- private void scheduleNotification(int type, long delayUs) {
- // ignore time notifications until seek is handled
- if (mSeeking && type == NOTIFY_TIME) {
- return;
- }
-
- if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
- mEventHandler.removeMessages(NOTIFY);
- Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
- mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
- }
-
- /** @hide */
- public void close() {
- mEventHandler.removeMessages(NOTIFY);
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- mHandlerThread = null;
- }
- }
-
- /** @hide */
- protected void finalize() {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- }
-
- /** @hide */
- public void onNotifyTime() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onNotifyTime: ");
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onPaused(boolean paused) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "onPaused: " + paused);
- if (mStopped) { // handle as seek if we were stopped
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- } else {
- mPausing = paused; // special handling if player disappeared
- mSeeking = false;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
- }
-
- /** @hide */
- public void onBuffering(boolean buffering) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
- mBuffering = buffering;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onStopped() {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "onStopped");
- mPaused = true;
- mStopped = true;
- mSeeking = false;
- mBuffering = false;
- scheduleNotification(NOTIFY_STOP, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onSeekComplete(MediaPlayer2Impl mp) {
- synchronized(this) {
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- }
-
- /** @hide */
- public void onNewPlayer() {
- if (mRefresh) {
- synchronized(this) {
- mStopped = false;
- mSeeking = true;
- mBuffering = false;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- }
- }
-
- private synchronized void notifySeek() {
- mSeeking = false;
- try {
- long timeUs = getCurrentTimeUs(true, false);
- if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
-
- for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
- if (listener == null) {
- break;
- }
- listener.onSeek(timeUs);
- }
- } catch (IllegalStateException e) {
- // we should not be there, but at least signal pause
- if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
- mPausing = true; // special handling if player disappeared
- notifyTimedEvent(false /* refreshTime */);
- }
- }
-
- private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
- SubtitleTrack track = trackData.first;
- byte[] data = trackData.second;
- track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
- }
-
- private synchronized void notifyStop() {
- for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
- if (listener == null) {
- break;
- }
- listener.onStop();
- }
- }
-
- private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
- int i = 0;
- for (; i < mListeners.length; i++) {
- if (mListeners[i] == listener || mListeners[i] == null) {
- break;
- }
- }
-
- // new listener
- if (i >= mListeners.length) {
- MediaTimeProvider.OnMediaTimeListener[] newListeners =
- new MediaTimeProvider.OnMediaTimeListener[i + 1];
- long[] newTimes = new long[i + 1];
- System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
- System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
- mListeners = newListeners;
- mTimes = newTimes;
- }
-
- if (mListeners[i] == null) {
- mListeners[i] = listener;
- mTimes[i] = MediaTimeProvider.NO_TIME;
- }
- return i;
- }
-
- public void notifyAt(
- long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
- mTimes[registerListener(listener)] = timeUs;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- if (DEBUG) Log.d(TAG, "scheduleUpdate");
- int i = registerListener(listener);
-
- if (!mStopped) {
- mTimes[i] = 0;
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
- }
-
- public void cancelNotifications(
- MediaTimeProvider.OnMediaTimeListener listener) {
- synchronized(this) {
- int i = 0;
- for (; i < mListeners.length; i++) {
- if (mListeners[i] == listener) {
- System.arraycopy(mListeners, i + 1,
- mListeners, i, mListeners.length - i - 1);
- System.arraycopy(mTimes, i + 1,
- mTimes, i, mTimes.length - i - 1);
- mListeners[mListeners.length - 1] = null;
- mTimes[mTimes.length - 1] = NO_TIME;
- break;
- } else if (mListeners[i] == null) {
- break;
- }
- }
-
- scheduleNotification(NOTIFY_TIME, 0 /* delay */);
- }
- }
-
- private synchronized void notifyTimedEvent(boolean refreshTime) {
- // figure out next callback
- long nowUs;
- try {
- nowUs = getCurrentTimeUs(refreshTime, true);
- } catch (IllegalStateException e) {
- // assume we paused until new player arrives
- mRefresh = true;
- mPausing = true; // this ensures that call succeeds
- nowUs = getCurrentTimeUs(refreshTime, true);
- }
- long nextTimeUs = nowUs;
-
- if (mSeeking) {
- // skip timed-event notifications until seek is complete
- return;
- }
-
- if (DEBUG) {
- StringBuilder sb = new StringBuilder();
- sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
- .append(nowUs).append(") from {");
- boolean first = true;
- for (long time: mTimes) {
- if (time == NO_TIME) {
- continue;
- }
- if (!first) sb.append(", ");
- sb.append(time);
- first = false;
- }
- sb.append("}");
- Log.d(TAG, sb.toString());
- }
-
- Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
- new Vector<MediaTimeProvider.OnMediaTimeListener>();
- for (int ix = 0; ix < mTimes.length; ix++) {
- if (mListeners[ix] == null) {
- break;
- }
- if (mTimes[ix] <= NO_TIME) {
- // ignore, unless we were stopped
- } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
- activatedListeners.add(mListeners[ix]);
- if (DEBUG) Log.d(TAG, "removed");
- mTimes[ix] = NO_TIME;
- } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
- nextTimeUs = mTimes[ix];
- }
- }
-
- if (nextTimeUs > nowUs && !mPaused) {
- // schedule callback at nextTimeUs
- if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
- mPlayer.notifyAt(nextTimeUs);
- } else {
- mEventHandler.removeMessages(NOTIFY);
- // no more callbacks
- }
-
- for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
- listener.onTimedEvent(nowUs);
- }
- }
-
- public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
- throws IllegalStateException {
- synchronized (this) {
- // we always refresh the time when the paused-state changes, because
- // we expect to have received the pause-change event delayed.
- if (mPaused && !refreshTime) {
- return mLastReportedTime;
- }
-
- try {
- mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
- mPaused = !mPlayer.isPlaying() || mBuffering;
- if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
- } catch (IllegalStateException e) {
- if (mPausing) {
- // if we were pausing, get last estimated timestamp
- mPausing = false;
- if (!monotonic || mLastReportedTime < mLastTimeUs) {
- mLastReportedTime = mLastTimeUs;
- }
- mPaused = true;
- if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
- return mLastReportedTime;
- }
- // TODO get time when prepared
- throw e;
- }
- if (monotonic && mLastTimeUs < mLastReportedTime) {
- /* have to adjust time */
- if (mLastReportedTime - mLastTimeUs > 1000000) {
- // schedule seeked event if time jumped significantly
- // TODO: do this properly by introducing an exception
- mStopped = false;
- mSeeking = true;
- scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
- }
- } else {
- mLastReportedTime = mLastTimeUs;
- }
-
- return mLastReportedTime;
- }
- }
-
- private class EventHandler extends Handler {
- public EventHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NOTIFY) {
- switch (msg.arg1) {
- case NOTIFY_TIME:
- notifyTimedEvent(true /* refreshTime */);
- break;
- case NOTIFY_STOP:
- notifyStop();
- break;
- case NOTIFY_SEEK:
- notifySeek();
- break;
- case NOTIFY_TRACK_DATA:
- notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
- break;
- }
- }
- }
- }
- }
-
private abstract class Task implements Runnable {
private final int mMediaCallType;
private final boolean mNeedToWaitForEventToComplete;
@@ -4651,6 +3620,17 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
&& getState() == PLAYER_STATE_ERROR) {
status = CALL_STATUS_INVALID_OPERATION;
} else {
+ if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
+ synchronized (mTaskLock) {
+ if (!mPendingTasks.isEmpty()) {
+ Task nextTask = mPendingTasks.get(0);
+ if (nextTask.mMediaCallType == mMediaCallType) {
+ throw new CommandSkippedException(
+ "consecutive seekTo is skipped except last one");
+ }
+ }
+ }
+ }
process();
}
} catch (IllegalStateException e) {
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
index a7eb30d0f596..0c1d1a2fc8d2 100644
--- a/media/java/android/media/update/ApiLoader.java
+++ b/media/java/android/media/update/ApiLoader.java
@@ -16,14 +16,64 @@
package android.media.update;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.PathClassLoader;
+
+import java.io.File;
+
/**
* @hide
*/
public final class ApiLoader {
+ @GuardedBy("this")
+ private static StaticProvider sMediaUpdatable;
+
+ private static final String UPDATE_PACKAGE = "com.android.media.update";
+ private static final String UPDATE_CLASS = "com.android.media.update.ApiFactory";
+ private static final String UPDATE_METHOD = "initialize";
+ private static final boolean REGISTER_UPDATE_DEPENDENCY = true;
+
private ApiLoader() { }
public static StaticProvider getProvider() {
- throw new RuntimeException("Use MediaSession/Browser instead of"
- + " hidden MediaSession2/Browser2 APIs.");
+ try {
+ return getMediaUpdatable();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (NameNotFoundException | ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
+ private static synchronized StaticProvider getMediaUpdatable()
+ throws NameNotFoundException, ReflectiveOperationException, RemoteException {
+ if (sMediaUpdatable != null) return sMediaUpdatable;
+
+ // TODO Figure out when to use which package (query media update service)
+ int flags = Build.IS_DEBUGGABLE ? 0 : PackageManager.MATCH_SYSTEM_ONLY;
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ UPDATE_PACKAGE, flags, UserHandle.myUserId());
+
+ if (REGISTER_UPDATE_DEPENDENCY) {
+ // Register a dependency to the updatable in order to be killed during updates
+ ActivityManager.getService().addPackageDependency(ai.packageName);
+ }
+
+ ClassLoader classLoader = new PathClassLoader(ai.sourceDir,
+ ai.nativeLibraryDir + File.pathSeparator + System.getProperty("java.library.path"),
+ ClassLoader.getSystemClassLoader().getParent());
+ return sMediaUpdatable = (StaticProvider) classLoader.loadClass(UPDATE_CLASS)
+ .getMethod(UPDATE_METHOD, ApplicationInfo.class).invoke(null, ai);
}
}
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 693a3d0b23df..352df811d42f 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -769,18 +769,6 @@ android_media_MediaPlayer2_seekTo(JNIEnv *env, jobject thiz, jlong msec, jint mo
NULL, NULL);
}
-static void
-android_media_MediaPlayer2_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
-{
- sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return;
- }
- ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
- process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
-}
-
static jint
android_media_MediaPlayer2_getState(JNIEnv *env, jobject thiz)
{
@@ -986,15 +974,15 @@ android_media_MediaPlayer2_isLooping(JNIEnv *env, jobject thiz)
}
static void
-android_media_MediaPlayer2_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)
+android_media_MediaPlayer2_setVolume(JNIEnv *env, jobject thiz, jfloat volume)
{
- ALOGV("setVolume: left %f right %f", (float) leftVolume, (float) rightVolume);
+ ALOGV("setVolume: volume %f", (float) volume);
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
+ process_media_player_call( env, thiz, mp->setVolume((float) volume), NULL, NULL );
}
static jbyteArray
@@ -1482,7 +1470,6 @@ static const JNINativeMethod gMethods[] = {
{"_setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer2_setSyncParams},
{"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer2_getSyncParams},
{"_seekTo", "(JI)V", (void *)android_media_MediaPlayer2_seekTo},
- {"_notifyAt", "(J)V", (void *)android_media_MediaPlayer2_notifyAt},
{"_pause", "()V", (void *)android_media_MediaPlayer2_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer2_isPlaying},
{"getCurrentPosition", "()J", (void *)android_media_MediaPlayer2_getCurrentPosition},
@@ -1494,7 +1481,7 @@ static const JNINativeMethod gMethods[] = {
{"getParameter", "(I)Ljava/lang/Object;", (void *)android_media_MediaPlayer2_getParameter},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping},
{"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping},
- {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume},
+ {"_setVolume", "(F)V", (void *)android_media_MediaPlayer2_setVolume},
{"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke},
{"native_init", "()V", (void *)android_media_MediaPlayer2_native_init},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup},
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index cdaabdcda20f..d0ca04bb07c2 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -184,7 +184,6 @@ public class DeviceDiscoveryService extends Service {
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
- intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index e645adc60b7c..03eb0d9aad5a 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -67,10 +67,6 @@ LOCAL_MULTILIB := both
LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
@@ -113,10 +109,6 @@ LOCAL_PACKAGE_NAME := CtsShim
LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
index 164fc5a5af3d..9855565c1335 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -26,15 +26,16 @@ class CutoutAvoidingToolbar : LinearLayout {
private var _insets: WindowInsets? = null
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@@ -81,8 +82,4 @@ class CutoutAvoidingToolbar : LinearLayout {
requestLayout()
}
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
index a4a3d3d835e0..fc7e8b008a54 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -17,7 +17,6 @@
package com.android.egg.paint
import android.content.Context
-import android.content.res.Resources
import android.graphics.*
import android.provider.Settings
import android.util.AttributeSet
@@ -26,7 +25,6 @@ import android.view.MotionEvent
import android.view.View
import android.view.WindowInsets
import java.util.concurrent.TimeUnit
-import android.util.Log
import android.provider.Settings.System
import org.json.JSONObject
@@ -86,11 +84,11 @@ public class Painting : View, SpotFilter.Plotter {
}
var bitmap: Bitmap? = null
- var paperColor : Int = 0xFFFFFFFF.toInt()
+ var paperColor: Int = 0xFFFFFFFF.toInt()
private var _paintCanvas: Canvas? = null
private val _bitmapLock = Object()
-
+
private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private var _lastX = 0f
private var _lastY = 0f
@@ -113,7 +111,9 @@ public class Painting : View, SpotFilter.Plotter {
FADE_TO_BLACK_CF
synchronized(_bitmapLock) {
- c.drawBitmap(bitmap, 0f, 0f, pt)
+ bitmap?.let {
+ c.drawBitmap(bitmap!!, 0f, 0f, pt)
+ }
}
invalidate()
}
@@ -122,18 +122,22 @@ public class Painting : View, SpotFilter.Plotter {
}
constructor(context: Context) : super(context) {
- init(null, 0)
+ init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
+ init()
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
+ init()
}
- private fun init(attrs: AttributeSet?, defStyle: Int) {
+ private fun init() {
loadDevicePressureData()
}
@@ -264,7 +268,7 @@ public class Painting : View, SpotFilter.Plotter {
super.onDraw(canvas)
bitmap?.let {
- canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+ canvas.drawBitmap(bitmap!!, 0f, 0f, _drawPaint)
}
}
@@ -330,8 +334,8 @@ public class Painting : View, SpotFilter.Plotter {
}
if (bits.width != oldBits.height || bits.height != oldBits.width) {
matrix.postScale(
- bits.width.toFloat()/oldBits.height,
- bits.height.toFloat()/oldBits.width)
+ bits.width.toFloat() / oldBits.height,
+ bits.height.toFloat() / oldBits.width)
}
c.matrix = matrix
}
@@ -350,9 +354,10 @@ public class Painting : View, SpotFilter.Plotter {
val invertPaint = Paint()
invertPaint.colorFilter = INVERT_CF
synchronized(_bitmapLock) {
- _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+ bitmap?.let {
+ _paintCanvas?.drawBitmap(bitmap!!, 0f, 0f, invertPaint)
+ }
}
invalidate()
}
}
-
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
index 86b11e7be81e..460fa3a7241f 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -17,19 +17,10 @@
package com.android.egg.paint
import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Rect
-import android.graphics.drawable.Drawable
-import android.text.TextPaint
-import android.transition.ChangeBounds
import android.transition.Transition
import android.transition.TransitionListenerAdapter
-import android.transition.TransitionManager
import android.util.AttributeSet
import android.view.*
-import android.view.animation.OvershootInterpolator
import android.widget.FrameLayout
class ToolbarView : FrameLayout {
@@ -44,15 +35,16 @@ class ToolbarView : FrameLayout {
}
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
@@ -70,8 +62,4 @@ class ToolbarView : FrameLayout {
return super.onApplyWindowInsets(insets)
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 7c8139928476..4801f62bae67 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
<uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index ba81278fd7da..0f065ab95e2d 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -228,4 +228,14 @@
<!-- Label for the notification channel containing notifications for embedded app operations [CHAR LIMIT=40] -->
<string name="wear_app_channel">Installing/uninstalling wear apps</string>
+ <!-- Description for the app installer notification channel [CHAR LIMIT=40] -->
+ <string name="app_installed_notification_channel_description">App installed notification</string>
+
+ <!-- Notification message shown in status bar when an application is successfully installed.
+ [CHAR LIMIT=30] -->
+ <string name="notification_installation_success_message">Successfully installed</string>
+
+ <!-- Notification shown in status bar when an application is successfully installed.
+ [CHAR LIMIT=50] -->
+ <string name="notification_installation_success_status">Successfully installed \u201c<xliff:g id="appname" example="Package Installer">%1$s</xliff:g>\u201d</string>
</resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
new file mode 100644
index 000000000000..2ebbefaef85b
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
@@ -0,0 +1,347 @@
+/*
+ * 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 com.android.packageinstaller;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+
+/**
+ * A util class that handle and post new app installed notifications.
+ */
+class PackageInstalledNotificationUtils {
+ private static final String TAG = PackageInstalledNotificationUtils.class.getSimpleName();
+
+ private static final String NEW_APP_INSTALLED_CHANNEL_ID_PREFIX = "INSTALLER:";
+ private static final String META_DATA_INSTALLER_NOTIFICATION_SMALL_ICON_KEY =
+ "com.android.packageinstaller.notification.smallIcon";
+ private static final String META_DATA_INSTALLER_NOTIFICATION_COLOR_KEY =
+ "com.android.packageinstaller.notification.color";
+
+ private static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
+
+ private final Context mContext;
+ private final NotificationManager mNotificationManager;
+
+ private final String mInstallerPackage;
+ private final String mInstallerAppLabel;
+ private final Icon mInstallerAppSmallIcon;
+ private final Integer mInstallerAppColor;
+
+ private final String mInstalledPackage;
+ private final String mInstalledAppLabel;
+ private final Icon mInstalledAppLargeIcon;
+
+ private final String mChannelId;
+
+ PackageInstalledNotificationUtils(@NonNull Context context, @NonNull String installerPackage,
+ @NonNull String installedPackage) {
+ mContext = context;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+ ApplicationInfo installerAppInfo;
+ ApplicationInfo installedAppInfo;
+
+ try {
+ installerAppInfo = context.getPackageManager().getApplicationInfo(installerPackage,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Should not happen
+ throw new IllegalStateException("Unable to get application info: " + installerPackage);
+ }
+ try {
+ installedAppInfo = context.getPackageManager().getApplicationInfo(installedPackage,
+ PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Should not happen
+ throw new IllegalStateException("Unable to get application info: " + installedPackage);
+ }
+ mInstallerPackage = installerPackage;
+ mInstallerAppLabel = getAppLabel(context, installerAppInfo, installerPackage);
+ mInstallerAppSmallIcon = getAppNotificationIcon(context, installerAppInfo);
+ mInstallerAppColor = getAppNotificationColor(context, installerAppInfo);
+
+ mInstalledPackage = installedPackage;
+ mInstalledAppLabel = getAppLabel(context, installedAppInfo, installerPackage);
+ mInstalledAppLargeIcon = getAppLargeIcon(installedAppInfo);
+
+ mChannelId = NEW_APP_INSTALLED_CHANNEL_ID_PREFIX + installerPackage;
+ }
+
+ /**
+ * Get app label from app's manifest.
+ *
+ * @param context A context of the current app
+ * @param appInfo Application info of targeted app
+ * @param packageName Package name of targeted app
+ * @return The label of targeted application, or package name if label is not found
+ */
+ private static String getAppLabel(@NonNull Context context, @NonNull ApplicationInfo appInfo,
+ @NonNull String packageName) {
+ CharSequence label = appInfo.loadSafeLabel(context.getPackageManager(),
+ DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+ | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE).toString();
+ if (label != null) {
+ return label.toString();
+ }
+ return packageName;
+ }
+
+ /**
+ * The app icon from app's manifest.
+ *
+ * @param appInfo Application info of targeted app
+ * @return App icon of targeted app, or Android default app icon if icon is not found
+ */
+ private static Icon getAppLargeIcon(@NonNull ApplicationInfo appInfo) {
+ if (appInfo.icon != 0) {
+ return Icon.createWithResource(appInfo.packageName, appInfo.icon);
+ } else {
+ return Icon.createWithResource("android", android.R.drawable.sym_def_app_icon);
+ }
+ }
+
+ /**
+ * Get notification icon from installer's manifest meta-data.
+ *
+ * @param context A context of the current app
+ * @param appInfo Installer application info
+ * @return Notification icon that listed in installer's manifest meta-data.
+ * If icon is not found in meta-data, then it returns Android default download icon.
+ */
+ private static Icon getAppNotificationIcon(@NonNull Context context,
+ @NonNull ApplicationInfo appInfo) {
+ if (appInfo.metaData == null) {
+ return Icon.createWithResource(context, R.drawable.ic_file_download);
+ }
+
+ int iconResId = appInfo.metaData.getInt(
+ META_DATA_INSTALLER_NOTIFICATION_SMALL_ICON_KEY, 0);
+ if (iconResId != 0) {
+ return Icon.createWithResource(appInfo.packageName, iconResId);
+ }
+ return Icon.createWithResource(context, R.drawable.ic_file_download);
+ }
+
+ /**
+ * Get notification color from installer's manifest meta-data.
+ *
+ * @param context A context of the current app
+ * @param appInfo Installer application info
+ * @return Notification color that listed in installer's manifest meta-data, or null if
+ * meta-data is not found.
+ */
+ private static Integer getAppNotificationColor(@NonNull Context context,
+ @NonNull ApplicationInfo appInfo) {
+ if (appInfo.metaData == null) {
+ return null;
+ }
+
+ int colorResId = appInfo.metaData.getInt(
+ META_DATA_INSTALLER_NOTIFICATION_COLOR_KEY, 0);
+ if (colorResId != 0) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ Resources resources = pm.getResourcesForApplication(appInfo.packageName);
+ return resources.getColor(colorResId, context.getTheme());
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Error while loading notification color: " + colorResId + " for "
+ + appInfo.packageName);
+ }
+ }
+ return null;
+ }
+
+ private static Intent getAppDetailIntent(@NonNull String packageName) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", packageName, null));
+ return intent;
+ }
+
+ private static Intent resolveIntent(@NonNull Context context, @NonNull Intent i) {
+ ResolveInfo result = context.getPackageManager().resolveActivity(i, 0);
+ if (result == null) {
+ return null;
+ }
+ return new Intent(i.getAction()).setClassName(result.activityInfo.packageName,
+ result.activityInfo.name);
+ }
+
+ private static Intent getAppStoreLink(@NonNull Context context,
+ @NonNull String installerPackageName, @NonNull String packageName) {
+ Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+ .setPackage(installerPackageName);
+
+ Intent result = resolveIntent(context, intent);
+ if (result != null) {
+ result.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ return result;
+ }
+ return null;
+ }
+
+ /**
+ * Create notification channel for showing apps installed notifications.
+ */
+ private void createChannel() {
+ NotificationChannel channel = new NotificationChannel(mChannelId, mInstallerAppLabel,
+ NotificationManager.IMPORTANCE_DEFAULT);
+ channel.setDescription(
+ mContext.getString(R.string.app_installed_notification_channel_description));
+ channel.enableVibration(false);
+ channel.setSound(null, null);
+ channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+ channel.setBlockableSystem(true);
+
+ mNotificationManager.createNotificationChannel(channel);
+ }
+
+ /**
+ * Returns a pending intent when user clicks on apps installed notification.
+ * It should launch the app if possible, otherwise it will return app store's app page.
+ * If app store's app page is not available, it will return Android app details page.
+ */
+ private PendingIntent getInstalledAppLaunchIntent() {
+ Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mInstalledPackage);
+
+ // If installed app does not have a launch intent, bring user to app store page
+ if (intent == null) {
+ intent = getAppStoreLink(mContext, mInstallerPackage, mInstalledPackage);
+ }
+
+ // If app store cannot handle this, bring user to app settings page
+ if (intent == null) {
+ intent = getAppDetailIntent(mInstalledPackage);
+ }
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext,
+ 0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ /**
+ * Returns a pending intent that starts installer's launch intent.
+ * If it doesn't have a launch intent, it will return installer's Android app details page.
+ */
+ private PendingIntent getInstallerEntranceIntent() {
+ Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mInstallerPackage);
+
+ // If installer does not have a launch intent, bring user to app settings page
+ if (intent == null) {
+ intent = getAppDetailIntent(mInstallerPackage);
+ }
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(mContext,
+ 0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ /**
+ * Returns a notification builder for grouped notifications.
+ */
+ private Notification.Builder getGroupNotificationBuilder() {
+ PendingIntent contentIntent = getInstallerEntranceIntent();
+
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, mInstallerAppLabel);
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, mChannelId)
+ .setSmallIcon(mInstallerAppSmallIcon)
+ .setGroup(mChannelId)
+ .setExtras(extras)
+ .setLocalOnly(true)
+ .setCategory(Notification.CATEGORY_STATUS)
+ .setContentIntent(contentIntent)
+ .setGroupSummary(true);
+
+ if (mInstallerAppColor != null) {
+ builder.setColor(mInstallerAppColor);
+ }
+ return builder;
+ }
+
+ /**
+ * Returns notification build for individual installed applications.
+ */
+ private Notification.Builder getAppInstalledNotificationBuilder() {
+ PendingIntent contentIntent = getInstalledAppLaunchIntent();
+
+ Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, mInstallerAppLabel);
+
+ String tickerText = String.format(
+ mContext.getString(R.string.notification_installation_success_status),
+ mInstalledAppLabel);
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, mChannelId)
+ .setAutoCancel(true)
+ .setSmallIcon(mInstallerAppSmallIcon)
+ .setContentTitle(mInstalledAppLabel)
+ .setContentText(mContext.getString(
+ R.string.notification_installation_success_message))
+ .setContentIntent(contentIntent)
+ .setTicker(tickerText)
+ .setCategory(Notification.CATEGORY_STATUS)
+ .setShowWhen(true)
+ .setWhen(System.currentTimeMillis())
+ .setLocalOnly(true)
+ .setGroup(mChannelId)
+ .addExtras(extras)
+ .setStyle(new Notification.BigTextStyle());
+
+ if (mInstalledAppLargeIcon != null) {
+ builder.setLargeIcon(mInstalledAppLargeIcon);
+ }
+ if (mInstallerAppColor != null) {
+ builder.setColor(mInstallerAppColor);
+ }
+ return builder;
+ }
+
+ /**
+ * Post new app installed notification.
+ */
+ void postAppInstalledNotification() {
+ createChannel();
+
+ // Post app installed notification
+ Notification.Builder appNotificationBuilder = getAppInstalledNotificationBuilder();
+ mNotificationManager.notify(mInstalledPackage, mInstalledPackage.hashCode(),
+ appNotificationBuilder.build());
+
+ // Post installer group notification
+ Notification.Builder groupNotificationBuilder = getGroupNotificationBuilder();
+ mNotificationManager.notify(mInstallerPackage, mInstallerPackage.hashCode(),
+ groupNotificationBuilder.build());
+ }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
index 67ac99fb12a6..1eb423e53267 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
@@ -19,16 +19,54 @@ package com.android.packageinstaller;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.net.Uri;
+import android.util.Log;
/**
* Receive new app installed broadcast and notify user new app installed.
*/
public class PackageInstalledReceiver extends BroadcastReceiver {
+ private static final String TAG = PackageInstalledReceiver.class.getSimpleName();
- private static final String TAG = "PackageInstalledReceiver";
+ private static final boolean DEBUG = false;
+ private static final boolean APP_INSTALLED_NOTIFICATION_ENABLED = false;
@Override
public void onReceive(Context context, Intent intent) {
- // TODO: Add logic to handle new app installed.
+ if (!APP_INSTALLED_NOTIFICATION_ENABLED) {
+ return;
+ }
+
+ String action = intent.getAction();
+
+ if (DEBUG) {
+ Log.i(TAG, "Received action: " + action);
+ }
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ Uri packageUri = intent.getData();
+ if (packageUri == null) {
+ return;
+ }
+
+ String packageName = packageUri.getSchemeSpecificPart();
+ if (packageName == null) {
+ Log.e(TAG, "No package name");
+ return;
+ }
+
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ if (DEBUG) {
+ Log.i(TAG, "Not new app, skip it: " + packageName);
+ }
+ return;
+ }
+
+ // TODO: Make sure the installer information here is accurate
+ String installer =
+ context.getPackageManager().getInstallerPackageName(packageName);
+ new PackageInstalledNotificationUtils(context, installer,
+ packageName).postAppInstalledNotification();
+ }
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 8c29a2520390..441dbac24928 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -16,7 +16,7 @@
*/
package com.android.packageinstaller;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.Manifest;
import android.annotation.NonNull;
@@ -281,7 +281,7 @@ public class PackageInstallerActivity extends AlertActivity {
@Override
protected void onCreate(Bundle icicle) {
- getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
super.onCreate(null);
diff --git a/packages/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
new file mode 100644
index 000000000000..c40a81791302
--- /dev/null
+++ b/packages/PrintSpooler/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_app {
+ name: "PrintSpooler",
+
+ resource_dirs: ["res"],
+
+ srcs: [
+ "src/**/*.java",
+ "src/com/android/printspooler/renderer/IPdfRenderer.aidl",
+ "src/com/android/printspooler/renderer/IPdfEditor.aidl",
+ ],
+
+ platform_apis: true,
+
+ jni_libs: ["libprintspooler_jni"],
+ static_libs: [
+ "android-support-v7-recyclerview",
+ "android-support-compat",
+ "android-support-media-compat",
+ "android-support-core-utils",
+ "android-support-core-ui",
+ "android-support-fragment",
+ "android-support-annotations",
+ ],
+}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
deleted file mode 100644
index e356f38f10b3..000000000000
--- a/packages/PrintSpooler/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_USE_AAPT2 := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
- src/com/android/printspooler/renderer/IPdfRenderer.aidl \
- src/com/android/printspooler/renderer/IPdfEditor.aidl
-
-LOCAL_PACKAGE_NAME := PrintSpooler
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- android-support-v7-recyclerview \
- android-support-compat \
- android-support-media-compat \
- android-support-core-utils \
- android-support-core-ui \
- android-support-fragment
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-annotations
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk
deleted file mode 100644
index 83e00ce089d2..000000000000
--- a/packages/PrintSpooler/tests/Android.mk
+++ /dev/null
@@ -1,19 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
new file mode 100644
index 000000000000..e88074ee4b9c
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+android_test {
+ name: "PrintSpoolerOutOfProcessTests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: ["android.test.runner.stubs"],
+ static_libs: [
+ "android-support-test",
+ "ub-uiautomator",
+ "mockito-target-minus-junit4",
+ "print-test-util-lib",
+ ],
+
+ sdk_version: "test_current",
+ test_suites: ["device-tests"],
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
deleted file mode 100644
index 161a60021e65..000000000000
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ /dev/null
@@ -1,30 +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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
-
-LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
index 7306d968a709..e407d7239546 100644
--- a/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/HelpUtils/src/com/android/settingslib/HelpUtils.java
@@ -187,17 +187,17 @@ public class HelpUtils {
if (sendPackageName && includePackageName) {
String[] packageNameKey =
- {resources.getString(android.R.string.config_help_package_name_key)};
+ {resources.getString(android.R.string.config_helpPackageNameKey)};
String[] packageNameValue =
- {resources.getString(android.R.string.config_help_package_name_value)};
+ {resources.getString(android.R.string.config_helpPackageNameValue)};
String helpIntentExtraKey =
- resources.getString(android.R.string.config_help_intent_extra_key);
+ resources.getString(android.R.string.config_helpIntentExtraKey);
String helpIntentNameKey =
- resources.getString(android.R.string.config_help_intent_name_key);
+ resources.getString(android.R.string.config_helpIntentNameKey);
String feedbackIntentExtraKey =
- resources.getString(android.R.string.config_feedback_intent_extra_key);
+ resources.getString(android.R.string.config_feedbackIntentExtraKey);
String feedbackIntentNameKey =
- resources.getString(android.R.string.config_feedback_intent_name_key);
+ resources.getString(android.R.string.config_feedbackIntentNameKey);
intent.putExtra(helpIntentExtraKey, packageNameKey);
intent.putExtra(helpIntentNameKey, packageNameValue);
intent.putExtra(feedbackIntentExtraKey, packageNameKey);
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
index 0f02abd94216..0748192fb1fc 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/layout/restricted_icon.xml
@@ -15,7 +15,7 @@
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/restricted_icon"
- android:layout_width="@*android:dimen/config_restricted_icon_size"
- android:layout_height="@*android:dimen/config_restricted_icon_size"
+ android:layout_width="@*android:dimen/config_restrictedIconSize"
+ android:layout_height="@*android:dimen/config_restrictedIconSize"
android:tint="?android:attr/colorAccent"
android:src="@*android:drawable/ic_info" />
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 738181d76c2a..e278c10a2c59 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -33,13 +33,13 @@ import java.util.Objects;
* support message dialog.
*/
public class RestrictedLockUtils {
- public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
- return getProfileOrDeviceOwner(context, null, userId);
+ public static EnforcedAdmin getProfileOrDeviceOwner(Context context, UserHandle user) {
+ return getProfileOrDeviceOwner(context, null, user);
}
public static EnforcedAdmin getProfileOrDeviceOwner(
- Context context, String enforcedRestriction, int userId) {
- if (userId == UserHandle.USER_NULL) {
+ Context context, String enforcedRestriction, UserHandle user) {
+ if (user == null) {
return null;
}
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
@@ -47,14 +47,14 @@ public class RestrictedLockUtils {
if (dpm == null) {
return null;
}
- ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
+ ComponentName adminComponent = dpm.getProfileOwnerAsUser(user);
if (adminComponent != null) {
- return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+ return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
}
- if (dpm.getDeviceOwnerUserId() == userId) {
+ if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {
adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
if (adminComponent != null) {
- return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+ return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
}
}
return null;
@@ -66,9 +66,9 @@ public class RestrictedLockUtils {
public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
int targetUserId = UserHandle.myUserId();
- if (admin != null && admin.userId != UserHandle.USER_NULL
- && isCurrentUserOrProfile(context, admin.userId)) {
- targetUserId = admin.userId;
+ if (admin != null && admin.user != null
+ && isCurrentUserOrProfile(context, admin.user.getIdentifier())) {
+ targetUserId = admin.user.getIdentifier();
}
intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction);
context.startActivityAsUser(intent, UserHandle.of(targetUserId));
@@ -81,8 +81,8 @@ public class RestrictedLockUtils {
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
}
int adminUserId = UserHandle.myUserId();
- if (admin.userId != UserHandle.USER_NULL) {
- adminUserId = admin.userId;
+ if (admin.user != null) {
+ adminUserId = admin.user.getIdentifier();
}
intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
}
@@ -91,13 +91,7 @@ public class RestrictedLockUtils {
public static boolean isCurrentUserOrProfile(Context context, int userId) {
UserManager um = context.getSystemService(UserManager.class);
- int[] userIds = um.getProfileIds(UserHandle.myUserId(), true);
- for (int i = 0; i < userIds.length; i++) {
- if (userIds[i] == userId) {
- return true;
- }
- }
- return false;
+ return um.getUserProfiles().contains(UserHandle.of(userId));
}
public static class EnforcedAdmin {
@@ -109,7 +103,8 @@ public class RestrictedLockUtils {
*/
@Nullable
public String enforcedRestriction = null;
- public int userId = UserHandle.USER_NULL;
+ @Nullable
+ public UserHandle user = null;
// We use this to represent the case where a policy is enforced by multiple admins.
public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
@@ -121,15 +116,15 @@ public class RestrictedLockUtils {
return enforcedAdmin;
}
- public EnforcedAdmin(ComponentName component, int userId) {
+ public EnforcedAdmin(ComponentName component, UserHandle user) {
this.component = component;
- this.userId = userId;
+ this.user = user;
}
- public EnforcedAdmin(ComponentName component, String enforcedRestriction, int userId) {
+ public EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user) {
this.component = component;
this.enforcedRestriction = enforcedRestriction;
- this.userId = userId;
+ this.user = user;
}
public EnforcedAdmin(EnforcedAdmin other) {
@@ -138,7 +133,7 @@ public class RestrictedLockUtils {
}
this.component = other.component;
this.enforcedRestriction = other.enforcedRestriction;
- this.userId = other.userId;
+ this.user = other.user;
}
public EnforcedAdmin() {
@@ -149,14 +144,14 @@ public class RestrictedLockUtils {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EnforcedAdmin that = (EnforcedAdmin) o;
- return userId == that.userId &&
+ return Objects.equals(user, that.user) &&
Objects.equals(component, that.component) &&
Objects.equals(enforcedRestriction, that.enforcedRestriction);
}
@Override
public int hashCode() {
- return Objects.hash(component, enforcedRestriction, userId);
+ return Objects.hash(component, enforcedRestriction, user);
}
@Override
@@ -164,7 +159,7 @@ public class RestrictedLockUtils {
return "EnforcedAdmin{" +
"component=" + component +
", enforcedRestriction='" + enforcedRestriction +
- ", userId=" + userId +
+ ", user=" + user +
'}';
}
}
diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
index af30425a511c..cbebbb32dc89 100644
--- a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
+++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
@@ -18,11 +18,14 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingMode="stack">
<item>
- <shape>
+ <shape
+ android:tint="?android:attr/colorForeground">
<corners
android:radius="20dp"/>
+ <solid
+ android:color="@android:color/transparent"/>
<stroke
- android:color="?android:attr/textColorSecondary"
+ android:color="#1f000000"
android:width="1dp"/>
<size
android:height="32dp"/>
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
index c26295ceaf59..8bf8fce4e36d 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
@@ -24,7 +24,7 @@ import android.widget.ArrayAdapter;
/**
* An ArrayAdapter which was used by {@link SettingsSpinner} with settings style.
*/
-public class SettingsSpinnerAdapter<CharSequence> extends ArrayAdapter {
+public class SettingsSpinnerAdapter<T> extends ArrayAdapter<T> {
/**
* Constructs a new SettingsSpinnerAdapter with the given context.
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
index e1f6cdf57101..5dbcb7952e88 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
@@ -16,8 +16,8 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/restricted_icon"
- android:layout_width="@*android:dimen/config_restricted_icon_size"
- android:layout_height="@*android:dimen/config_restricted_icon_size"
+ android:layout_width="@*android:dimen/config_restrictedIconSize"
+ android:layout_height="@*android:dimen/config_restrictedIconSize"
android:tint="?android:attr/colorAccent"
android:src="@*android:drawable/ic_info"
android:gravity="end|center_vertical" />
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index c03ba9a93294..1457fcfadc89 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -58,7 +58,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
public static Drawable getRestrictedPadlock(Context context) {
Drawable restrictedPadlock = context.getDrawable(android.R.drawable.ic_info);
final int iconSize = context.getResources().getDimensionPixelSize(
- android.R.dimen.config_restricted_icon_size);
+ android.R.dimen.config_restrictedIconSize);
TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
int colorAccent = ta.getColor(0, 0);
@@ -164,6 +164,17 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
/**
+ * @return the UserHandle for a userId. Return null for USER_NULL
+ */
+ private static UserHandle getUserHandleOf(@UserIdInt int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ return null;
+ } else {
+ return UserHandle.of(userId);
+ }
+ }
+
+ /**
* Filter a set of device admins based on a predicate {@code check}. This is equivalent to
* {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
* returning a zero/one/many-type thing.
@@ -183,11 +194,13 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
if (admins == null) {
return null;
}
+
+ final UserHandle user = getUserHandleOf(userId);
EnforcedAdmin enforcedAdmin = null;
for (ComponentName admin : admins) {
if (check.isEnforcing(dpm, admin, userId)) {
if (enforcedAdmin == null) {
- enforcedAdmin = new EnforcedAdmin(admin, userId);
+ enforcedAdmin = new EnforcedAdmin(admin, user);
} else {
return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
@@ -211,7 +224,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
IPackageManager ipm = AppGlobals.getPackageManager();
try {
if (ipm.getBlockUninstallForUser(packageName, userId)) {
- return getProfileOrDeviceOwner(context, userId);
+ return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
}
} catch (RemoteException e) {
// Nothing to do
@@ -230,7 +243,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
IPackageManager ipm = AppGlobals.getPackageManager();
try {
if (ipm.isPackageSuspendedForUser(packageName, userId)) {
- return getProfileOrDeviceOwner(context, userId);
+ return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
}
} catch (RemoteException | IllegalArgumentException e) {
// Nothing to do
@@ -245,14 +258,15 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
if (dpm == null) {
return null;
}
- EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+ EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
boolean permitted = true;
if (admin != null) {
permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
packageName, userId);
}
int managedProfileId = getManagedProfileId(context, userId);
- EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+ EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context,
+ getUserHandleOf(managedProfileId));
boolean permittedByProfileAdmin = true;
if (profileAdmin != null) {
permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component,
@@ -298,14 +312,15 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
if (dpm == null) {
return null;
}
- EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+ EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
boolean permitted = true;
if (admin != null) {
permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
packageName, userId);
}
int managedProfileId = getManagedProfileId(context, userId);
- EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+ EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context,
+ getUserHandleOf(managedProfileId));
boolean permittedByProfileAdmin = true;
if (profileAdmin != null) {
permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
@@ -365,7 +380,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
if (!isAccountTypeDisabled) {
return null;
}
- return getProfileOrDeviceOwner(context, userId);
+ return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
}
/**
@@ -377,7 +392,8 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
*/
public static EnforcedAdmin checkIfMeteredDataRestricted(Context context,
String packageName, int userId) {
- final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context, userId);
+ final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context,
+ getUserHandleOf(userId));
if (enforcedAdmin == null) {
return null;
}
@@ -402,7 +418,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
return null;
}
ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
- return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+ return new EnforcedAdmin(adminComponent, getUserHandleOf(UserHandle.myUserId()));
}
/**
@@ -434,10 +450,11 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
return null;
}
EnforcedAdmin enforcedAdmin = null;
+ final UserHandle user = getUserHandleOf(userId);
for (ComponentName admin : admins) {
if (check.isEnforcing(dpm, admin, userId)) {
if (enforcedAdmin == null) {
- enforcedAdmin = new EnforcedAdmin(admin, userId);
+ enforcedAdmin = new EnforcedAdmin(admin, user);
} else {
return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
@@ -488,13 +505,14 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
if (admins == null) {
continue;
}
+ final UserHandle user = getUserHandleOf(userInfo.id);
final boolean isSeparateProfileChallengeEnabled =
sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
for (ComponentName admin : admins) {
if (!isSeparateProfileChallengeEnabled) {
if (check.isEnforcing(dpm, admin, userInfo.id)) {
if (enforcedAdmin == null) {
- enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ enforcedAdmin = new EnforcedAdmin(admin, user);
} else {
return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
@@ -511,7 +529,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
if (enforcedAdmin == null) {
- enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ enforcedAdmin = new EnforcedAdmin(admin, user);
} else {
return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
@@ -535,7 +553,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
if (adminComponent != null) {
return new EnforcedAdmin(
- adminComponent, enforcedRestriction, dpm.getDeviceOwnerUserId());
+ adminComponent, enforcedRestriction, dpm.getDeviceOwnerUser());
}
return null;
}
@@ -556,7 +574,7 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
if (adminComponent != null) {
- return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+ return new EnforcedAdmin(adminComponent, enforcedRestriction, getUserHandleOf(userId));
}
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
index 3102239c2c9e..3c451127508d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/DefaultAppInfo.java
@@ -25,7 +25,6 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.IconDrawableFactory;
import com.android.settingslib.widget.CandidateInfo;
@@ -46,8 +45,8 @@ public class DefaultAppInfo extends CandidateInfo {
this(context, pm, uid, cn, null /* summary */, true /* enabled */);
}
- public DefaultAppInfo(Context context, PackageManager pm, PackageItemInfo info) {
- this(context, pm, info, null /* summary */, true /* enabled */);
+ public DefaultAppInfo(Context context, PackageManager pm, int uid, PackageItemInfo info) {
+ this(context, pm, uid, info, null /* summary */, true /* enabled */);
}
public DefaultAppInfo(Context context, PackageManager pm, int uid, ComponentName cn,
@@ -61,12 +60,12 @@ public class DefaultAppInfo extends CandidateInfo {
this.summary = summary;
}
- public DefaultAppInfo(Context context, PackageManager pm, PackageItemInfo info,
+ public DefaultAppInfo(Context context, PackageManager pm, int uid, PackageItemInfo info,
String summary, boolean enabled) {
super(enabled);
mContext = context;
mPm = pm;
- userId = UserHandle.myUserId();
+ userId = uid;
packageItemInfo = info;
componentName = null;
this.summary = summary;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4aca2bb2c54d..7124096e31b8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -267,8 +267,10 @@ public class BluetoothEventManager {
cachedDevice = mDeviceManager.addDevice(device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
- } else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
- // Dispatch device add callback to show bonded BT device in discovery mode
+ } else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+ &&!cachedDevice.getDevice().isConnected()) {
+ // Dispatch device add callback to show bonded but
+ // not connected devices in discovery mode
dispatchDeviceAdded(cachedDevice);
}
cachedDevice.setRssi(rssi);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 750a8438c00d..a2e30df9ac5c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -60,11 +60,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private short mRssi;
private final List<LocalBluetoothProfile> mProfiles =
- new ArrayList<LocalBluetoothProfile>();
+ Collections.synchronizedList(new ArrayList<>());
// List of profiles that were previously in mProfiles, but have been removed
private final List<LocalBluetoothProfile> mRemovedProfiles =
- new ArrayList<LocalBluetoothProfile>();
+ Collections.synchronizedList(new ArrayList<>());
// Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
private boolean mLocalNapRoleConnected;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
index 1091e1601b89..36b70dfe2297 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/HelpUtilsTest.java
@@ -70,17 +70,17 @@ public class HelpUtilsTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mContext.getResources().getString(R.string.config_help_package_name_key))
+ when(mContext.getResources().getString(R.string.config_helpPackageNameKey))
.thenReturn(PACKAGE_NAME_KEY);
- when(mContext.getResources().getString(R.string.config_help_package_name_value))
+ when(mContext.getResources().getString(R.string.config_helpPackageNameValue))
.thenReturn(PACKAGE_NAME_VALUE);
- when(mContext.getResources().getString(R.string.config_help_intent_extra_key))
+ when(mContext.getResources().getString(R.string.config_helpIntentExtraKey))
.thenReturn(HELP_INTENT_EXTRA_KEY);
- when(mContext.getResources().getString(R.string.config_help_intent_name_key))
+ when(mContext.getResources().getString(R.string.config_helpIntentNameKey))
.thenReturn(HELP_INTENT_NAME_KEY);
- when(mContext.getResources().getString(R.string.config_feedback_intent_extra_key))
+ when(mContext.getResources().getString(R.string.config_feedbackIntentExtraKey))
.thenReturn(FEEDBACK_INTENT_EXTRA_KEY);
- when(mContext.getResources().getString(R.string.config_feedback_intent_name_key))
+ when(mContext.getResources().getString(R.string.config_feedbackIntentNameKey))
.thenReturn(FEEDBACK_INTENT_NAME_KEY);
when(mActivity.getPackageManager()).thenReturn(mPackageManager);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index fc8d9db20607..88ac8ce5fae5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -156,7 +156,7 @@ public class RestrictedLockUtilsTest {
final EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal
.checkIfKeyguardFeaturesDisabled(mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
- assertThat(enforcedAdmin).isEqualTo(new EnforcedAdmin(mAdmin1, mUserId));
+ assertThat(enforcedAdmin).isEqualTo(new EnforcedAdmin(mAdmin1, UserHandle.of(mUserId)));
}
@Test
@@ -189,12 +189,12 @@ public class RestrictedLockUtilsTest {
// Querying the parent should return the policy, since it affects the parent.
EnforcedAdmin parent = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
- assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
// Querying the child should return that too.
EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
- assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
// Querying for some unrelated feature should return nothing. Nothing!
assertThat(RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
@@ -224,7 +224,7 @@ public class RestrictedLockUtilsTest {
// Querying the child should still return the policy.
EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mProfileId);
- assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
}
@Test
@@ -251,7 +251,7 @@ public class RestrictedLockUtilsTest {
// Querying the child should still return the policy.
EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
- assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
}
/**
@@ -278,7 +278,7 @@ public class RestrictedLockUtilsTest {
// Parent should get the policy.
EnforcedAdmin parent = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
- assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+ assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
// Profile should not get the policy.
EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java
index 01f0d78ede1a..a92a2dd8c11a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/DefaultAppInfoTest.java
@@ -18,8 +18,8 @@ package com.android.settingslib.applications;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -72,7 +72,7 @@ public class DefaultAppInfoTest {
@Test
public void initInfoWithActivityInfo_shouldLoadInfo() {
mPackageItemInfo.packageName = "test";
- mInfo = new DefaultAppInfo(mContext, mPackageManager, mPackageItemInfo);
+ mInfo = new DefaultAppInfo(mContext, mPackageManager, 0 /* uid */, mPackageItemInfo);
mInfo.loadLabel();
Drawable icon = mInfo.loadIcon();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 8745a330311a..da1354be63d2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -662,6 +662,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.ANGLE_ENABLED_APP,
GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
+ dumpSetting(s, p,
+ Settings.Global.GPU_DEBUG_LAYER_APP,
+ GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ce503b373dbe..822c39b6a71d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
@@ -55,6 +56,7 @@
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
<!-- Development tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.SET_DEBUG_APP" />
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
new file mode 100644
index 000000000000..ba4eb5f48528
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -0,0 +1,91 @@
+/*
+ * 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.plugins;
+
+import android.hardware.Sensor;
+import android.hardware.TriggerEventListener;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Allows for additional sensors to be retrieved from
+ * {@link com.android.systemui.util.AsyncSensorManager}.
+ */
+@ProvidesInterface(action = SensorManagerPlugin.ACTION, version = SensorManagerPlugin.VERSION)
+public interface SensorManagerPlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_SENSOR_MANAGER";
+ int VERSION = 1;
+
+ /**
+ * Registers for trigger events from the sensor. Trigger events are one-shot and need to
+ * re-registered in order for them to be fired again.
+ * @param sensor
+ * @param listener
+ * @see android.hardware.SensorManager#requestTriggerSensor(
+ * android.hardware.TriggerEventListener, android.hardware.Sensor)
+ */
+ void registerTriggerEvent(Sensor sensor, TriggerEventListener listener);
+
+ /**
+ * Unregisters trigger events from the sensor.
+ * @param sensor
+ * @param listener
+ */
+ void unregisterTriggerEvent(Sensor sensor, TriggerEventListener listener);
+
+ interface TriggerEventListener {
+ void onTrigger(TriggerEvent event);
+ }
+
+ class Sensor {
+ public static int TYPE_WAKE_LOCK_SCREEN = 1;
+
+ int mType;
+
+ public int getType() {
+ return mType;
+ }
+
+ public Sensor(int type) {
+ mType = type;
+ }
+ }
+
+ class TriggerEvent {
+ Sensor mSensor;
+ int mVendorType;
+
+ /**
+ * Creates a trigger event
+ * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
+ * @param vendorType The vendor type, which should be unique for each type of sensor,
+ * e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
+ */
+ public TriggerEvent(Sensor sensor, int vendorType) {
+ mSensor = sensor;
+ mVendorType = vendorType;
+ }
+
+ public Sensor getSensor() {
+ return mSensor;
+ }
+
+ public int getVendorType() {
+ return mVendorType;
+ }
+ }
+}
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7a38899f37f7..f138685e9810 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,8 +24,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
- android:background="@color/notification_guts_bg_color"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
+ android:background="@color/notification_guts_bg_color">
<!-- Package Info -->
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436dea9207..d033057cdb78 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
android:paddingEnd="@dimen/status_bar_padding_end"
android:orientation="horizontal"
>
- <ViewStub
- android:id="@+id/operator_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/operator_name" />
<FrameLayout
android:layout_height="match_parent"
android:layout_width="0dp"
@@ -70,6 +65,12 @@
android:layout_width="match_parent"
android:clipChildren="false"
>
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
+
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e1c71fae7559..42e19aace0c3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -761,6 +761,8 @@
<string name="quick_settings_cast_device_default_description">Ready to cast</string>
<!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_detail_empty_text">No devices available</string>
+ <!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
@@ -1999,6 +2001,9 @@
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_details">Open details.</string>
+ <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>
+
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
index c6a086dcfbdc..c3815e4cee78 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
@@ -14,7 +14,6 @@
package com.android.systemui.shared.plugins;
-import android.annotation.Nullable;
import android.content.Context;
import android.os.Looper;
@@ -26,11 +25,16 @@ public interface PluginInitializer {
Looper getBgLooper();
/**
- * This Runnable is run on the bg looper during initialization of {@link PluginManagerImpl}.
+ * Called from the bg looper during initialization of {@link PluginManagerImpl}.
*/
- @Nullable Runnable getBgInitCallback();
+ void onPluginManagerInit();
String[] getWhitelistedPlugins(Context context);
PluginEnabler getPluginEnabler(Context context);
+
+ /**
+ * Called from {@link PluginManagerImpl#handleWtfs()}.
+ */
+ void handleWtfs();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index a54e08eba23d..87f29342b167 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -74,11 +74,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private final boolean isDebuggable;
private final PluginPrefs mPluginPrefs;
private final PluginEnabler mPluginEnabler;
+ private final PluginInitializer mPluginInitializer;
private ClassLoaderFilter mParentClassLoader;
private boolean mListening;
private boolean mHasOneShot;
private Looper mLooper;
- private boolean mWtfsSet;
public PluginManagerImpl(Context context, PluginInitializer initializer) {
this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
@@ -87,7 +87,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
@VisibleForTesting
PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
- UncaughtExceptionHandler defaultHandler, PluginInitializer initializer) {
+ UncaughtExceptionHandler defaultHandler, final PluginInitializer initializer) {
mContext = context;
mFactory = factory;
mLooper = initializer.getBgLooper();
@@ -95,15 +95,18 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
mPluginPrefs = new PluginPrefs(mContext);
mPluginEnabler = initializer.getPluginEnabler(mContext);
+ mPluginInitializer = initializer;
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
- Runnable bgRunnable = initializer.getBgInitCallback();
- if (bgRunnable != null) {
- new Handler(mLooper).post(bgRunnable);
- }
+ new Handler(mLooper).post(new Runnable() {
+ @Override
+ public void run() {
+ initializer.onPluginManagerInit();
+ }
+ });
}
public String[] getWhitelistedPlugins() {
@@ -299,16 +302,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
}
public void handleWtfs() {
- if (!mWtfsSet) {
- mWtfsSet = true;
- Log.setWtfHandler(new Log.TerribleFailureHandler() {
- @Override
- public void onTerribleFailure(String tag, Log.TerribleFailure what,
- boolean system) {
- throw new CrashWhilePluginActiveException(what);
- }
- });
- }
+ mPluginInitializer.handleWtfs();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -391,7 +385,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
}
}
- private class CrashWhilePluginActiveException extends RuntimeException {
+ public static class CrashWhilePluginActiveException extends RuntimeException {
public CrashWhilePluginActiveException(Throwable throwable) {
super(throwable);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java
index 5a28a5e28d91..7c8c23eba73b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java
@@ -48,7 +48,7 @@ public abstract class RotationWatcher {
if (!mIsWatching) {
try {
WindowManagerGlobal.getWindowManagerService().watchRotation(mWatcher,
- mContext.getDisplay().getDisplayId());
+ mContext.getDisplayId());
mIsWatching = true;
} catch (RemoteException e) {
Log.w(TAG, "Failed to set rotation watcher", e);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 2daa33bb1ea5..112e06785bee 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -373,11 +373,11 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mPendingLockCheck.cancel(false);
mPendingLockCheck = null;
}
+ displayDefaultSecurityMessage();
}
@Override
public void onResume(int reason) {
- displayDefaultSecurityMessage();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fe1fe1aba908..2c821b25f0a5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -178,7 +178,8 @@ public class Dependency extends SystemUI {
getDependency(ActivityStarter.class));
mProviders.put(AsyncSensorManager.class, () ->
- new AsyncSensorManager(mContext.getSystemService(SensorManager.class)));
+ new AsyncSensorManager(mContext.getSystemService(SensorManager.class),
+ getDependency(PluginManager.class)));
mProviders.put(BluetoothController.class, () ->
new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER)));
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 198a4e6cedb8..b1463a3c53ea 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -143,9 +143,6 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
mSeparatedView.setBackground(mSeparatedViewBackground);
updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
mOldHeight = mList.getMeasuredHeight();
- mList.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- updatePosition());
updateRotation();
} else {
return;
@@ -155,6 +152,8 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
if (newHeight != mOldHeight) {
animateChild(mOldHeight, newHeight);
}
+
+ post(() -> updatePaddingAndGravityIfTooTall());
post(() -> updatePosition());
}
@@ -241,7 +240,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
mSeparatedView.setLayoutParams(separatedViewLayoutParams);
- setGravity(p.gravity);
+ setGravity(rotateGravityRight(getGravity()));
}
private void swapDimens(View v) {
@@ -299,7 +298,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
mSeparatedView.setLayoutParams(separatedViewLayoutParams);
- setGravity(p.gravity);
+ setGravity(rotateGravityLeft(getGravity()));
}
private int rotateGravityLeft(int gravity) {
@@ -447,6 +446,46 @@ public class HardwareUiLayout extends LinearLayout implements Tunable {
mAnimator.start();
}
+ // If current power menu height larger then screen height, remove padding to break power menu
+ // alignment and set menu center vertical within the screen.
+ private void updatePaddingAndGravityIfTooTall() {
+ int defaultTopPadding;
+ int viewsTotalHeight;
+ int separatedViewTopMargin;
+ int screenHeight;
+ int totalHeight;
+ int targetGravity;
+ MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
+ switch (RotationUtils.getRotation(getContext())) {
+ case RotationUtils.ROTATION_LANDSCAPE:
+ defaultTopPadding = getPaddingLeft();
+ viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
+ separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+ screenHeight = getMeasuredWidth();
+ targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
+ break;
+ case RotationUtils.ROTATION_SEASCAPE:
+ defaultTopPadding = getPaddingRight();
+ viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
+ separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+ screenHeight = getMeasuredWidth();
+ targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
+ break;
+ default: // Portrait
+ defaultTopPadding = getPaddingTop();
+ viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
+ separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
+ screenHeight = getMeasuredHeight();
+ targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
+ break;
+ }
+ totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
+ if (totalHeight >= screenHeight) {
+ setPadding(0, 0, 0, 0);
+ setGravity(targetGravity);
+ }
+ }
+
@Override
public ViewOutlineProvider getOutlineProvider() {
return super.getOutlineProvider();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d24d82bd7ee..3007b6e68b78 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -736,14 +736,19 @@ public class ScreenDecorations extends SystemUI implements Tunable {
switch (gravity) {
case Gravity.TOP:
out.set(displayCutout.getBoundingRectTop());
+ break;
case Gravity.LEFT:
out.set(displayCutout.getBoundingRectLeft());
+ break;
case Gravity.BOTTOM:
out.set(displayCutout.getBoundingRectBottom());
+ break;
case Gravity.RIGHT:
out.set(displayCutout.getBoundingRectRight());
+ break;
+ default:
+ out.setEmpty();
}
- out.setEmpty();
}
private void localBounds(Rect out) {
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 6d790668995e..449ed8c3bcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -14,7 +14,7 @@
package com.android.systemui;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.app.Activity;
import android.app.AlertDialog;
@@ -69,7 +69,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener
.setPositiveButton(R.string.slice_permission_allow, this)
.setOnDismissListener(this)
.create();
- dialog.getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ dialog.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
dialog.show();
TextView t1 = dialog.getWindow().getDecorView().findViewById(R.id.text1);
t1.setText(getString(R.string.slice_permission_text_1, app2));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index c90861e4af52..7d77929556a5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -200,7 +200,9 @@ public abstract class BiometricDialogView extends LinearLayout {
mLastState = STATE_NONE;
updateState(STATE_AUTHENTICATING);
- title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
+ CharSequence titleText = mBundle.getCharSequence(BiometricPrompt.KEY_TITLE);
+
+ title.setText(titleText);
title.setSelected(true);
positive.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 701394763fbd..77f7ad4f3a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -16,6 +16,8 @@
package com.android.systemui.doze;
+import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
+
import android.annotation.AnyThread;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -39,8 +41,10 @@ import android.util.Log;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AlarmTimeout;
+import com.android.systemui.util.AsyncSensorManager;
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
@@ -112,8 +116,8 @@ public class DozeSensors {
DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
true /* reports touch coordinates */,
true /* touchscreen */),
- new TriggerSensor(
- findSensorWithType(config.wakeLockScreenSensorType()),
+ new PluginTriggerSensor(
+ new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
true /* configured */,
DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
@@ -375,7 +379,7 @@ public class DozeSensors {
mHandler.post(mWakeLock.wrap(() -> {
if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
boolean sensorPerformsProxCheck = false;
- if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
+ if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
int subType = (int) event.values[0];
MetricsLogger.action(
mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
@@ -418,6 +422,49 @@ public class DozeSensors {
}
}
+ /**
+ * A Sensor that is injected via plugin.
+ */
+ private class PluginTriggerSensor extends TriggerSensor {
+
+ private final SensorManagerPlugin.Sensor mPluginSensor;
+ private final SensorManagerPlugin.TriggerEventListener mTriggerEventListener = (event) -> {
+ onTrigger(null);
+ };
+
+ PluginTriggerSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
+ int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+ super(null, setting, configured, pulseReason, reportsTouchCoordinates,
+ requiresTouchscreen);
+ mPluginSensor = sensor;
+ }
+
+ @Override
+ public void updateListener() {
+ if (!mConfigured) return;
+ AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
+ if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
+ asyncSensorManager.requestPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+ mRegistered = true;
+ if (DEBUG) Log.d(TAG, "requestPluginTriggerSensor");
+ } else if (mRegistered) {
+ asyncSensorManager.cancelPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+ mRegistered = false;
+ if (DEBUG) Log.d(TAG, "cancelPluginTriggerSensor");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("{mRegistered=").append(mRegistered)
+ .append(", mRequested=").append(mRequested)
+ .append(", mDisabled=").append(mDisabled)
+ .append(", mConfigured=").append(mConfigured)
+ .append(", mSensor=").append(mPluginSensor).append("}").toString();
+ }
+
+ }
+
private class WakeScreenSensor extends TriggerSensor {
WakeScreenSensor() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 4a6786832df0..df763151cdd7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -16,7 +16,7 @@
package com.android.systemui.media;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.app.Activity;
import android.app.AlertDialog;
@@ -151,7 +151,7 @@ public class MediaProjectionPermissionActivity extends Activity
((CheckBox) mDialog.findViewById(R.id.remember)).setOnCheckedChangeListener(this);
final Window w = mDialog.getWindow();
w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- w.addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
mDialog.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
index ac0a226080bf..95029c013ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
@@ -16,29 +16,33 @@ package com.android.systemui.plugins;
import android.content.Context;
import android.os.Looper;
+import android.util.Log;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.shared.plugins.PluginEnabler;
import com.android.systemui.shared.plugins.PluginInitializer;
-import com.android.systemui.R;
+import com.android.systemui.shared.plugins.PluginManagerImpl;
public class PluginInitializerImpl implements PluginInitializer {
+
+ /**
+ * True if WTFs should lead to crashes
+ */
+ private static final boolean WTFS_SHOULD_CRASH = false;
+ private boolean mWtfsSet;
+
@Override
public Looper getBgLooper() {
return Dependency.get(Dependency.BG_LOOPER);
}
@Override
- public Runnable getBgInitCallback() {
- return new Runnable() {
- @Override
- public void run() {
- // Plugin dependencies that don't have another good home can go here, but
- // dependencies that have better places to init can happen elsewhere.
- Dependency.get(PluginDependencyProvider.class)
- .allowPluginDependency(ActivityStarter.class);
- }
- };
+ public void onPluginManagerInit() {
+ // Plugin dependencies that don't have another good home can go here, but
+ // dependencies that have better places to init can happen elsewhere.
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(ActivityStarter.class);
}
@Override
@@ -49,4 +53,18 @@ public class PluginInitializerImpl implements PluginInitializer {
public PluginEnabler getPluginEnabler(Context context) {
return new PluginEnablerImpl(context);
}
+
+ @Override
+ public void handleWtfs() {
+ if (WTFS_SHOULD_CRASH && !mWtfsSet) {
+ mWtfsSet = true;
+ Log.setWtfHandler(new Log.TerribleFailureHandler() {
+ @Override
+ public void onTerribleFailure(String tag, Log.TerribleFailure what,
+ boolean system) {
+ throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
+ }
+ });
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index ed78048c8746..921db6901626 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
import java.util.LinkedHashMap;
import java.util.Set;
@@ -58,16 +59,18 @@ public class CastTile extends QSTileImpl<BooleanState> {
private final CastController mController;
private final CastDetailAdapter mDetailAdapter;
private final KeyguardMonitor mKeyguard;
+ private final NetworkController mNetworkController;
private final Callback mCallback = new Callback();
private final ActivityStarter mActivityStarter;
private Dialog mDialog;
- private boolean mRegistered;
+ private boolean mWifiConnected;
public CastTile(QSHost host) {
super(host);
mController = Dependency.get(CastController.class);
mDetailAdapter = new CastDetailAdapter();
mKeyguard = Dependency.get(KeyguardMonitor.class);
+ mNetworkController = Dependency.get(NetworkController.class);
mActivityStarter = Dependency.get(ActivityStarter.class);
}
@@ -87,10 +90,12 @@ public class CastTile extends QSTileImpl<BooleanState> {
if (listening) {
mController.addCallback(mCallback);
mKeyguard.addCallback(mCallback);
+ mNetworkController.addCallback(mSignalCallback);
} else {
mController.setDiscovering(false);
mController.removeCallback(mCallback);
mKeyguard.removeCallback(mCallback);
+ mNetworkController.removeCallback(mSignalCallback);
}
}
@@ -112,6 +117,9 @@ public class CastTile extends QSTileImpl<BooleanState> {
@Override
protected void handleClick() {
+ if (getState().state == Tile.STATE_UNAVAILABLE) {
+ return;
+ }
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
showDetail(true);
@@ -164,13 +172,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
if (!state.value && connecting) {
state.label = mContext.getString(R.string.quick_settings_connecting);
}
- state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
: R.drawable.ic_qs_cast_off);
+ if (mWifiConnected) {
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.secondaryLabel = "";
+ state.contentDescription = state.contentDescription + ","
+ + mContext.getString(R.string.accessibility_quick_settings_open_details);
+ state.expandedAccessibilityClassName = Button.class.getName();
+ } else {
+ state.state = Tile.STATE_UNAVAILABLE;
+ String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
+ state.secondaryLabel = noWifi;
+ state.contentDescription = state.contentDescription + ", " + mContext.getString(
+ R.string.accessibility_quick_settings_not_available, noWifi);
+ }
mDetailAdapter.updateItems(devices);
- state.expandedAccessibilityClassName = Button.class.getName();
- state.contentDescription = state.contentDescription + ","
- + mContext.getString(R.string.accessibility_quick_settings_open_details);
}
@Override
@@ -192,6 +209,22 @@ public class CastTile extends QSTileImpl<BooleanState> {
: mContext.getString(R.string.quick_settings_cast_device_default_name);
}
+ private final NetworkController.SignalCallback mSignalCallback =
+ new NetworkController.SignalCallback() {
+ @Override
+ public void setWifiIndicators(boolean enabled,
+ NetworkController.IconState statusIcon,
+ NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
+ String description, boolean isTransient, String statusLabel) {
+ // statusIcon.visible has the connected status information
+ boolean enabledAndConnected = enabled && qsIcon.visible;
+ if (enabledAndConnected != mWifiConnected) {
+ mWifiConnected = enabledAndConnected;
+ refreshState();
+ }
+ }
+ };
+
private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
@Override
public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
index 2c384d0f4d80..21a33b0271db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
+
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
@@ -85,6 +87,7 @@ public final class AmbientPulseManager extends AlertingNotificationManager {
for (OnAmbientChangedListener listener : mListeners) {
listener.onAmbientStateChanged(entry, false);
}
+ entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 9d773edec551..18151d0e794a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -54,10 +54,10 @@ public class KeyguardAffordanceView extends ImageView {
public static final float MAX_ICON_SCALE_AMOUNT = 1.5f;
public static final float MIN_ICON_SCALE_AMOUNT = 0.8f;
+ protected final int mDarkIconColor;
+ protected final int mNormalColor;
private final int mMinBackgroundRadius;
private final Paint mCirclePaint;
- private final int mDarkIconColor;
- private final int mNormalColor;
private final ArgbEvaluator mColorInterpolator;
private final FlingAnimationUtils mFlingAnimationUtils;
private float mCircleRadius;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0c5f39198b4f..a00eac4adea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,14 +19,14 @@ package com.android.systemui.statusbar;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.admin.DevicePolicyManager;
-import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
+import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
@@ -106,6 +106,7 @@ public class KeyguardIndicationController {
private final DevicePolicyManager mDevicePolicyManager;
private boolean mDozing;
+ private float mDarkAmount;
/**
* Creates a new KeyguardIndicationController and registers callbacks.
@@ -298,6 +299,15 @@ public class KeyguardIndicationController {
if (mVisible) {
// Walk down a precedence-ordered list of what indication
// should be shown based on user or device state
+ if (mDozing) {
+ if (!TextUtils.isEmpty(mTransientIndication)) {
+ mTextView.setTextColor(Color.WHITE);
+ mTextView.switchIndication(mTransientIndication);
+ }
+ updateAlphas();
+ return;
+ }
+
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
int userId = KeyguardUpdateMonitor.getCurrentUser();
String trustGrantedIndication = getTrustGrantedIndication();
@@ -335,6 +345,14 @@ public class KeyguardIndicationController {
}
}
+ private void updateAlphas() {
+ if (!TextUtils.isEmpty(mTransientIndication)) {
+ mTextView.setAlpha(1f);
+ } else {
+ mTextView.setAlpha(1f - mDarkAmount);
+ }
+ }
+
// animates textView - textView moves up and bounces down
private void animateText(KeyguardIndicationTextView textView, String indication) {
int yTranslation = mContext.getResources().getInteger(
@@ -492,6 +510,14 @@ public class KeyguardIndicationController {
pw.println(" computePowerIndication(): " + computePowerIndication());
}
+ public void setDarkAmount(float darkAmount) {
+ if (mDarkAmount == darkAmount) {
+ return;
+ }
+ mDarkAmount = darkAmount;
+ updateAlphas();
+ }
+
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
public static final int HIDE_DELAY_MS = 5000;
private int mLastSuccessiveErrorMessage = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index e89e6e89bc07..2db99453e36c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -256,9 +256,9 @@ public class NotificationMediaManager implements Dumpable {
private boolean isMediaNotification(NotificationData.Entry entry) {
// TODO: confirm that there's a valid media key
- return entry.getExpandedContentView() != null &&
- entry.getExpandedContentView()
- .findViewById(com.android.internal.R.id.media_actions) != null;
+ return entry.row.getExpandedContentView() != null
+ && entry.row.getExpandedContentView().findViewById(
+ com.android.internal.R.id.media_actions) != null;
}
private void clearCurrentMediaNotificationSession() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index d8f7b6142dd8..7fa042655e53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -436,7 +436,9 @@ public class NotificationShelf extends ActivatableNotificationView implements
public boolean onPreDraw() {
boolean animatingY = ViewState.isAnimatingY(icon);
if (!animatingY) {
- observer.removeOnPreDrawListener(this);
+ if (observer.isAlive()) {
+ observer.removeOnPreDrawListener(this);
+ }
icon.setTag(TAG_CONTINUOUS_CLIPPING, null);
return true;
}
@@ -453,7 +455,9 @@ public class NotificationShelf extends ActivatableNotificationView implements
@Override
public void onViewDetachedFromWindow(View v) {
if (v == icon) {
- observer.removeOnPreDrawListener(predrawListener);
+ if (observer.isAlive()) {
+ observer.removeOnPreDrawListener(predrawListener);
+ }
icon.setTag(TAG_CONTINUOUS_CLIPPING, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index d6719f0a03e1..78a5817c32b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -22,6 +22,7 @@ import android.annotation.IntDef;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Comparator;
@@ -39,6 +40,7 @@ public class StatusBarStateController {
= (o1, o2) -> Integer.compare(o1.rank, o2.rank);
private final ArrayList<RankedListener> mListeners = new ArrayList<>();
+ private boolean mIsDozing;
private int mState;
private int mLastState;
private boolean mLeaveOpenOnKeyguardHide;
@@ -57,6 +59,11 @@ public class StatusBarStateController {
return mState;
}
+ /**
+ * Update the status bar state
+ * @param state see {@link StatusBarState} for valid options
+ * @return {@code true} if the state changed, else {@code false}
+ */
public boolean setState(int state) {
if (state > MAX_STATE || state < MIN_STATE) {
throw new IllegalArgumentException("Invalid state " + state);
@@ -82,6 +89,32 @@ public class StatusBarStateController {
return true;
}
+ public boolean isDozing() {
+ return mIsDozing;
+ }
+
+ /**
+ * Update the dozing state from {@link StatusBar}'s perspective
+ * @param isDozing well, are we dozing?
+ * @return {@code true} if the state changed, else {@code false}
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ public boolean setIsDozing(boolean isDozing) {
+ if (mIsDozing == isDozing) {
+ return false;
+ }
+
+ mIsDozing = isDozing;
+
+ synchronized (mListeners) {
+ for (RankedListener rl : new ArrayList<>(mListeners)) {
+ rl.listener.onDozingChanged(isDozing);
+ }
+ }
+
+ return true;
+ }
+
public boolean goingToFullShade() {
return mState == StatusBarState.SHADE && mLeaveOpenOnKeyguardHide;
}
@@ -144,23 +177,49 @@ public class StatusBarStateController {
return StatusBarState.toShortString(state);
}
+ private class RankedListener {
+ private final StateListener listener;
+ private final int rank;
+
+ private RankedListener(StateListener l, int r) {
+ listener = l;
+ rank = r;
+ }
+ }
+
+ /**
+ * Listener for StatusBarState updates
+ */
public interface StateListener {
+
+ /**
+ * Callback before the new state is applied, for those who need to preempt the change
+ * @param oldState state before the change
+ * @param newState new state to be applied in {@link #onStateChanged}
+ */
public default void onStatePreChange(int oldState, int newState) {
}
+ /**
+ * Callback after all listeners have had a chance to update based on the state change
+ */
public default void onStatePostChange() {
}
+ /**
+ * Required callback. Get the new state and do what you will with it. Keep in mind that
+ * other listeners are typically unordered and don't rely on your work being done before
+ * other peers
+ *
+ * Only called if the state is actually different
+ * @param newState the new {@link StatusBarState}
+ */
public void onStateChanged(int newState);
- }
-
- private class RankedListener {
- private final StateListener listener;
- private final int rank;
- private RankedListener(StateListener l, int r) {
- listener = l;
- rank = r;
- }
+ /**
+ * Callback to be notified when Dozing changes. Dozing is stored separately from state.
+ * @param isDozing {@code true} if dozing according to {@link StatusBar}
+ */
+ public default void onDozingChanged(boolean isDozing) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2450e448c4f7..24665eac76a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -491,6 +491,10 @@ public class CarStatusBar extends StatusBar implements
@Override
public void onStateChanged(int newState) {
super.onStateChanged(newState);
+ if (mFullscreenUserSwitcher == null) {
+ return; // Not using the full screen user switcher.
+ }
+
if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
if (!mFullscreenUserSwitcher.isVisible()) {
// Current execution path continues to set state after this, thus we deffer the
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 d097c8e706ba..fbf12ed39561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -50,7 +50,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
-import android.widget.RemoteViews;
import androidx.annotation.Nullable;
@@ -102,11 +101,6 @@ public class NotificationData {
public boolean autoRedacted; // whether the redacted notification was generated by us
public int targetSdk;
private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
- public RemoteViews cachedContentView;
- public RemoteViews cachedBigContentView;
- public RemoteViews cachedHeadsUpContentView;
- public RemoteViews cachedPublicContentView;
- public RemoteViews cachedAmbientContentView;
public CharSequence remoteInputText;
public List<SnoozeCriterion> snoozeCriteria;
public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
@@ -178,14 +172,6 @@ public class NotificationData {
}
}
- public View getExpandedContentView() {
- return row.getPrivateLayout().getExpandedChild();
- }
-
- public View getPublicContentView() {
- return row.getPublicLayout().getContractedChild();
- }
-
public void notifyFullScreenIntentLaunched() {
setInterruption();
lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
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 a3e982e77522..28d339aaeab2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,6 +18,10 @@ package com.android.systemui.statusbar.notification;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.NotificationRemoteInputManager
.FORCE_REMOTE_INPUT_HISTORY;
+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;
import android.annotation.Nullable;
import android.app.Notification;
@@ -71,6 +75,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
+import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -440,25 +445,48 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
}
private void addEntry(NotificationData.Entry shadeEntry) {
- if (shouldHeadsUp(shadeEntry)) {
- mHeadsUpManager.showNotification(shadeEntry);
- // Mark as seen immediately
- setNotificationShown(shadeEntry.notification);
- }
- if (shouldPulse(shadeEntry)) {
- mAmbientPulseManager.showNotification(shadeEntry);
- }
addNotificationViews(shadeEntry);
mCallback.onNotificationAdded(shadeEntry);
}
+ /**
+ * Adds the entry to the respective alerting manager if the content view was inflated and
+ * the entry should still alert.
+ *
+ * @param entry entry to add
+ * @param inflatedFlags flags representing content views that were inflated
+ */
+ private void showAlertingView(NotificationData.Entry entry,
+ @InflationFlag int inflatedFlags) {
+ if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
+ // Possible for shouldHeadsUp to change between the inflation starting and ending.
+ // If it does and we no longer need to heads up, we should free the view.
+ if (shouldHeadsUp(entry)) {
+ mHeadsUpManager.showNotification(entry);
+ // Mark as seen immediately
+ setNotificationShown(entry.notification);
+ } else {
+ entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
+ }
+ }
+ if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
+ if (shouldPulse(entry)) {
+ mAmbientPulseManager.showNotification(entry);
+ } else {
+ entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
+ }
+ }
+ }
+
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @InflationFlag int inflatedFlags) {
mPendingNotifications.remove(entry.key);
// If there was an async task started after the removal, we don't want to add it back to
// the list, otherwise we might get leaks.
boolean isNew = mNotificationData.get(entry.key) == null;
if (isNew && !entry.row.isRemoved()) {
+ showAlertingView(entry, inflatedFlags);
addEntry(entry);
} else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
mVisualStabilityManager.onLowPriorityUpdated(entry);
@@ -636,7 +664,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
row.setSmartActions(entry.smartActions);
- row.updateNotification(entry);
+ row.setEntry(entry);
+
+ row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, shouldHeadsUp(entry));
+ row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, shouldPulse(entry));
+ row.inflateViews();
}
protected void addNotificationViews(NotificationData.Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index bce613a33859..23492aa62e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -17,12 +17,19 @@
package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+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;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -83,6 +90,7 @@ import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -429,12 +437,59 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- public void updateNotification(NotificationData.Entry entry) {
+ /**
+ * Set the entry for the row.
+ *
+ * @param entry the entry this row is tied to
+ */
+ public void setEntry(@NonNull NotificationData.Entry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
+ cacheIsSystemNotification();
+ }
+
+ /**
+ * Inflate views based off the inflation flags set. Inflation happens asynchronously.
+ */
+ public void inflateViews() {
mNotificationInflater.inflateNotificationViews();
+ }
- cacheIsSystemNotification();
+ /**
+ * Marks a content view as freeable, setting it so that future inflations do not reinflate
+ * and ensuring that the view is freed when it is safe to remove.
+ *
+ * @param inflationFlag flag corresponding to the content view to be freed
+ */
+ public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
+ // View should not be reinflated in the future
+ updateInflationFlag(inflationFlag, false);
+ Runnable freeViewRunnable = () ->
+ mNotificationInflater.freeNotificationView(inflationFlag);
+ switch (inflationFlag) {
+ case FLAG_CONTENT_VIEW_HEADS_UP:
+ getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
+ freeViewRunnable);
+ break;
+ case FLAG_CONTENT_VIEW_AMBIENT:
+ getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
+ freeViewRunnable);
+ getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
+ freeViewRunnable);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Update whether or not a content view should be inflated.
+ *
+ * @param flag the flag corresponding to the content view
+ * @param shouldInflate true if it should be inflated, false if it should not
+ */
+ public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
+ mNotificationInflater.updateInflationFlag(flag, shouldInflate);
}
/**
@@ -581,7 +636,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
headsUpHeight = mMaxHeadsUpHeight;
}
NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_HEADSUP);
+ VISIBLE_TYPE_HEADSUP);
if (headsUpWrapper != null) {
headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
}
@@ -2616,6 +2671,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
}
+ public View getExpandedContentView() {
+ return getPrivateLayout().getExpandedChild();
+ }
+
public void setLegacy(boolean legacy) {
for (NotificationContentView l : mLayouts) {
l.setLegacy(legacy);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 4963a0c6ae01..78564515a2c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -23,9 +23,11 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -40,12 +42,12 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -107,6 +109,10 @@ public class NotificationContentView extends FrameLayout {
private NotificationGroupManager mGroupManager;
private RemoteInputController mRemoteInputController;
private Runnable mExpandedVisibleListener;
+ /**
+ * List of listeners for when content views become inactive (i.e. not the showing view).
+ */
+ private final ArrayMap<View, Runnable> mOnContentViewInactiveListeners = new ArrayMap<>();
private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
= new ViewTreeObserver.OnPreDrawListener() {
@@ -516,6 +522,14 @@ public class NotificationContentView extends FrameLayout {
removeView(mAmbientChild);
}
if (child == null) {
+ mAmbientChild = null;
+ mAmbientWrapper = null;
+ if (mVisibleType == VISIBLE_TYPE_AMBIENT) {
+ mVisibleType = VISIBLE_TYPE_CONTRACTED;
+ }
+ if (mTransformationStartVisibleType == VISIBLE_TYPE_AMBIENT) {
+ mTransformationStartVisibleType = UNDEFINED;
+ }
return;
}
addView(child);
@@ -1162,6 +1176,7 @@ public class NotificationContentView extends FrameLayout {
public void onNotificationUpdated(NotificationData.Entry entry) {
mStatusBarNotification = entry.notification;
+ mOnContentViewInactiveListeners.clear();
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateAllSingleLineViews();
if (mContractedChild != null) {
@@ -1188,6 +1203,7 @@ public class NotificationContentView extends FrameLayout {
updateSingleLineView();
updateAmbientSingleLineView();
}
+
private void updateSingleLineView() {
if (mIsChildInGroup) {
boolean isNewView = mSingleLineView == null;
@@ -1223,53 +1239,44 @@ public class NotificationContentView extends FrameLayout {
return;
}
- boolean enableSmartReplies = (mSmartReplyConstants.isEnabled()
+ Notification notification = entry.notification.getNotification();
+
+ Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+ entry.notification.getNotification().findRemoteInputActionPair(false /*freeform */);
+ Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
+ notification.findRemoteInputActionPair(true /*freeform */);
+
+ boolean enableAppGeneratedSmartReplies = (mSmartReplyConstants.isEnabled()
&& (!mSmartReplyConstants.requiresTargetingP()
- || entry.targetSdk >= Build.VERSION_CODES.P));
+ || entry.targetSdk >= Build.VERSION_CODES.P));
- boolean hasRemoteInput = false;
RemoteInput remoteInputWithChoices = null;
- PendingIntent pendingIntentWithChoices = null;
+ PendingIntent pendingIntentWithChoices= null;
CharSequence[] choices = null;
-
- Notification.Action[] actions = entry.notification.getNotification().actions;
- if (actions != null) {
- for (Notification.Action a : actions) {
- if (a.getRemoteInputs() == null) {
- continue;
- }
- for (RemoteInput ri : a.getRemoteInputs()) {
- boolean showRemoteInputView = ri.getAllowFreeFormInput();
- boolean showSmartReplyView = enableSmartReplies
- && (ArrayUtils.isEmpty(ri.getChoices())
- || (showRemoteInputView && !ArrayUtils.isEmpty(entry.smartReplies)));
- if (showRemoteInputView) {
- hasRemoteInput = true;
- }
- if (showSmartReplyView) {
- remoteInputWithChoices = ri;
- pendingIntentWithChoices = a.actionIntent;
- if (!ArrayUtils.isEmpty(ri.getChoices())) {
- choices = ri.getChoices();
- } else {
- choices = entry.smartReplies;
- }
- }
- if (showRemoteInputView || showSmartReplyView) {
- break;
- }
- }
- }
- }
-
- applyRemoteInput(entry, hasRemoteInput);
+ if (enableAppGeneratedSmartReplies
+ && remoteInputActionPair != null
+ && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())) {
+ // app generated smart replies
+ remoteInputWithChoices = remoteInputActionPair.first;
+ pendingIntentWithChoices = remoteInputActionPair.second.actionIntent;
+ choices = remoteInputActionPair.first.getChoices();
+ } else if (!ArrayUtils.isEmpty(entry.smartReplies)
+ && freeformRemoteInputActionPair != null
+ && freeformRemoteInputActionPair.second.getAllowGeneratedReplies()) {
+ // system generated smart replies
+ remoteInputWithChoices = freeformRemoteInputActionPair.first;
+ pendingIntentWithChoices = freeformRemoteInputActionPair.second.actionIntent;
+ choices = entry.smartReplies;
+ }
+
+ applyRemoteInput(entry, freeformRemoteInputActionPair != null);
applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices, entry, choices);
}
- private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) {
+ private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
View bigContentView = mExpandedChild;
if (bigContentView != null) {
- mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
+ mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput,
mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput,
mExpandedWrapper);
} else {
@@ -1284,7 +1291,8 @@ public class NotificationContentView extends FrameLayout {
View headsUpContentView = mHeadsUpChild;
if (headsUpContentView != null) {
- mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
+ mHeadsUpRemoteInput = applyRemoteInput(
+ headsUpContentView, entry, hasFreeformRemoteInput,
mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput, mHeadsUpWrapper);
} else {
mHeadsUpRemoteInput = null;
@@ -1370,8 +1378,8 @@ public class NotificationContentView extends FrameLayout {
mExpandedSmartReplyView =
applySmartReplyView(mExpandedChild, remoteInput, pendingIntent, entry, choices);
if (mExpandedSmartReplyView != null && remoteInput != null
- && remoteInput.getChoices() != null && remoteInput.getChoices().length > 0) {
- mSmartReplyController.smartRepliesAdded(entry, remoteInput.getChoices().length);
+ && choices != null && choices.length > 0) {
+ mSmartReplyController.smartRepliesAdded(entry, choices.length);
}
}
}
@@ -1626,6 +1634,58 @@ public class NotificationContentView extends FrameLayout {
fireExpandedVisibleListenerIfVisible();
}
+ /**
+ * Set a one-shot listener to run when a given content view becomes inactive.
+ *
+ * @param visibleType visible type corresponding to the content view to listen
+ * @param listener runnable to run once when the content view becomes inactive
+ */
+ public void performWhenContentInactive(int visibleType, Runnable listener) {
+ View view = getViewForVisibleType(visibleType);
+ // View is already inactive
+ if (view == null || isContentViewInactive(visibleType)) {
+ listener.run();
+ return;
+ }
+ mOnContentViewInactiveListeners.put(view, listener);
+ }
+
+ /**
+ * Whether or not the content view is inactive. This means it should not be visible
+ * or the showing content as removing it would cause visual jank.
+ *
+ * @param visibleType visible type corresponding to the content view to be removed
+ * @return true if the content view is inactive, false otherwise
+ */
+ public boolean isContentViewInactive(int visibleType) {
+ View view = getViewForVisibleType(visibleType);
+ return isContentViewInactive(view);
+ }
+
+ /**
+ * Whether or not the content view is inactive.
+ *
+ * @param view view to see if its inactive
+ * @return true if the view is inactive, false o/w
+ */
+ private boolean isContentViewInactive(View view) {
+ if (view == null) {
+ return true;
+ }
+ return view.getVisibility() != VISIBLE && getViewForVisibleType(mVisibleType) != view;
+ }
+
+ @Override
+ protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
+ super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
+ if (isContentViewInactive(child)) {
+ Runnable listener = mOnContentViewInactiveListeners.remove(child);
+ if (listener != null) {
+ listener.run();
+ }
+ }
+ }
+
public void setIsLowPriority(boolean isLowPriority) {
mIsLowPriority = isLowPriority;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index aa4765a349b4..ea1892be1b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -16,12 +16,17 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
+
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
@@ -35,6 +40,8 @@ import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.Assert;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -52,14 +59,64 @@ import java.util.concurrent.atomic.AtomicInteger;
public class NotificationInflater {
public static final String TAG = "NotificationInflater";
- @VisibleForTesting
- static final int FLAG_REINFLATE_ALL = ~0;
- private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
- @VisibleForTesting
- static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
- private static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1<<2;
- private static final int FLAG_REINFLATE_PUBLIC_VIEW = 1<<3;
- private static final int FLAG_REINFLATE_AMBIENT_VIEW = 1<<4;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ prefix = {"FLAG_CONTENT_VIEW_"},
+ value = {
+ FLAG_CONTENT_VIEW_CONTRACTED,
+ FLAG_CONTENT_VIEW_EXPANDED,
+ FLAG_CONTENT_VIEW_HEADS_UP,
+ FLAG_CONTENT_VIEW_AMBIENT,
+ FLAG_CONTENT_VIEW_PUBLIC,
+ FLAG_CONTENT_VIEW_ALL})
+ public @interface InflationFlag {}
+ /**
+ * The default, contracted view. Seen when the shade is pulled down and in the lock screen
+ * if there is no worry about content sensitivity.
+ */
+ public static final int FLAG_CONTENT_VIEW_CONTRACTED = 1;
+
+ /**
+ * The expanded view. Seen when the user expands a notification.
+ */
+ public static final int FLAG_CONTENT_VIEW_EXPANDED = 1 << 1;
+
+ /**
+ * The heads up view. Seen when a high priority notification peeks in from the top.
+ */
+ public static final int FLAG_CONTENT_VIEW_HEADS_UP = 1 << 2;
+
+ /**
+ * The ambient view. Seen when a high priority notification is received and the phone
+ * is dozing.
+ */
+ public static final int FLAG_CONTENT_VIEW_AMBIENT = 1 << 3;
+
+ /**
+ * The public view. This is a version of the contracted view that hides sensitive
+ * information and is used on the lock screen if we determine that the notification's
+ * content should be hidden.
+ */
+ public static final int FLAG_CONTENT_VIEW_PUBLIC = 1 << 4;
+
+ public static final int FLAG_CONTENT_VIEW_ALL = ~0;
+
+ /**
+ * Content views that must be inflated at all times.
+ */
+ @InflationFlag
+ private static final int REQUIRED_INFLATION_FLAGS =
+ FLAG_CONTENT_VIEW_CONTRACTED
+ | FLAG_CONTENT_VIEW_EXPANDED
+ | FLAG_CONTENT_VIEW_PUBLIC;
+
+ /**
+ * The set of content views to inflate.
+ */
+ @InflationFlag
+ private int mInflationFlags = REQUIRED_INFLATION_FLAGS;
+
private static final InflationExecutor EXECUTOR = new InflationExecutor();
private final ExpandableNotificationRow mRow;
@@ -71,6 +128,7 @@ public class NotificationInflater {
private InflationCallback mCallback;
private boolean mRedactAmbient;
private List<Notification.Action> mSmartActions;
+ private final ArrayMap<Integer, RemoteViews> mCachedContentViews = new ArrayMap<>();
public NotificationInflater(ExpandableNotificationRow row) {
mRow = row;
@@ -89,10 +147,10 @@ public class NotificationInflater {
if (childInGroup != mIsChildInGroup) {
mIsChildInGroup = childInGroup;
if (mIsLowPriority) {
- int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
+ int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
inflateNotificationViews(flags);
}
- } ;
+ }
}
public void setUsesIncreasedHeight(boolean usesIncreasedHeight) {
@@ -117,38 +175,67 @@ public class NotificationInflater {
if (mRow.getEntry() == null) {
return;
}
- inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
+ inflateNotificationViews(FLAG_CONTENT_VIEW_AMBIENT);
}
}
/**
+ * Set whether or not a particular content view is needed and whether or not it should be
+ * inflated. These flags will be used when we inflate or reinflate.
+ *
+ * @param flag the {@link InflationFlag} corresponding to the view that should/should not be
+ * inflated
+ * @param shouldInflate true if the view should be inflated, false otherwise
+ */
+ public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
+ if (shouldInflate) {
+ mInflationFlags |= flag;
+ } else if ((REQUIRED_INFLATION_FLAGS & flag) == 0) {
+ mInflationFlags &= ~flag;
+ }
+ }
+
+ /**
+ * Add flags for which content views should be inflated in addition to those already set.
+ *
+ * @param flags a set of {@link InflationFlag} corresponding to content views that should be
+ * inflated
+ */
+ public void addInflationFlags(@InflationFlag int flags) {
+ mInflationFlags |= flags;
+ }
+
+ /**
* Inflate all views of this notification on a background thread. This is asynchronous and will
* notify the callback once it's finished.
*/
public void inflateNotificationViews() {
- inflateNotificationViews(FLAG_REINFLATE_ALL);
+ inflateNotificationViews(mInflationFlags);
}
/**
- * Reinflate all views for the specified flags on a background thread. This is asynchronous and
- * will notify the callback once it's finished.
+ * Inflate all views for the specified flags on a background thread. This is asynchronous and
+ * will notify the callback once it's finished. If the content view is already inflated, this
+ * will reinflate it.
*
- * @param reInflateFlags flags which views should be reinflated. Use {@link #FLAG_REINFLATE_ALL}
- * to reinflate all of views.
+ * @param reInflateFlags flags which views should be inflated. Should be a subset of
+ * {@link NotificationInflater#mInflationFlags} as only those will be
+ * inflated/reinflated.
*/
- @VisibleForTesting
- void inflateNotificationViews(int reInflateFlags) {
+ private void inflateNotificationViews(@InflationFlag int reInflateFlags) {
if (mRow.isRemoved()) {
// We don't want to reinflate anything for removed notifications. Otherwise views might
// be readded to the stack, leading to leaks. This may happen with low-priority groups
// where the removal of already removed children can lead to a reinflation.
return;
}
+ // Only inflate the ones that are set.
+ reInflateFlags |= mInflationFlags;
StatusBarNotification sbn = mRow.getEntry().notification;
- AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mRow,
- mIsLowPriority,
- mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
- mCallback, mRemoteViewClickHandler, mSmartActions);
+ AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mCachedContentViews,
+ mRow, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
+ mUsesIncreasedHeadsUpHeight, mRedactAmbient, mCallback, mRemoteViewClickHandler,
+ mSmartActions);
if (mCallback != null && mCallback.doInflateSynchronous()) {
task.onPostExecute(task.doInBackground());
} else {
@@ -157,38 +244,80 @@ public class NotificationInflater {
}
@VisibleForTesting
- InflationProgress inflateNotificationViews(int reInflateFlags,
+ InflationProgress inflateNotificationViews(@InflationFlag int reInflateFlags,
Notification.Builder builder, Context packageContext) {
InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority,
mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
mRedactAmbient, packageContext);
- apply(result, reInflateFlags, mRow, mRedactAmbient, mRemoteViewClickHandler, null);
+ apply(result, reInflateFlags, mCachedContentViews, mRow, mRedactAmbient,
+ mRemoteViewClickHandler, null);
return result;
}
- private static InflationProgress createRemoteViews(int reInflateFlags,
+ /**
+ * Frees the content view associated with the inflation flag. Will only succeed if the
+ * view is safe to remove.
+ *
+ * @param inflateFlag the flag corresponding to the content view which should be freed
+ */
+ public void freeNotificationView(@InflationFlag int inflateFlag) {
+ if ((mInflationFlags & inflateFlag) != 0) {
+ // The view should still be inflated.
+ return;
+ }
+ switch (inflateFlag) {
+ case FLAG_CONTENT_VIEW_HEADS_UP:
+ if (mRow.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) {
+ mRow.getPrivateLayout().setHeadsUpChild(null);
+ mCachedContentViews.remove(FLAG_CONTENT_VIEW_HEADS_UP);
+ }
+ break;
+ case FLAG_CONTENT_VIEW_AMBIENT:
+ boolean privateSafeToRemove = mRow.getPrivateLayout().isContentViewInactive(
+ VISIBLE_TYPE_AMBIENT);
+ boolean publicSafeToRemove = mRow.getPublicLayout().isContentViewInactive(
+ VISIBLE_TYPE_AMBIENT);
+ if (privateSafeToRemove) {
+ mRow.getPrivateLayout().setAmbientChild(null);
+ }
+ if (publicSafeToRemove) {
+ mRow.getPublicLayout().setAmbientChild(null);
+ }
+ if (privateSafeToRemove && publicSafeToRemove) {
+ mCachedContentViews.remove(FLAG_CONTENT_VIEW_AMBIENT);
+ }
+ break;
+ case FLAG_CONTENT_VIEW_CONTRACTED:
+ case FLAG_CONTENT_VIEW_EXPANDED:
+ case FLAG_CONTENT_VIEW_PUBLIC:
+ default:
+ break;
+ }
+ }
+
+ private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags,
Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
Context packageContext) {
InflationProgress result = new InflationProgress();
isLowPriority = isLowPriority && !isChildInGroup;
- if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
}
- if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
result.newExpandedView = createExpandedView(builder, isLowPriority);
}
- if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
}
- if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
result.newPublicView = builder.makePublicContentView();
}
- if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
: builder.makeAmbientNotification();
}
@@ -199,18 +328,20 @@ public class NotificationInflater {
return result;
}
- public static CancellationSignal apply(InflationProgress result, int reInflateFlags,
+ public static CancellationSignal apply(InflationProgress result,
+ @InflationFlag int reInflateFlags, ArrayMap<Integer, RemoteViews> cachedContentViews,
ExpandableNotificationRow row, boolean redactAmbient,
RemoteViews.OnClickHandler remoteViewClickHandler,
@Nullable InflationCallback callback) {
- NotificationData.Entry entry = row.getEntry();
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
- int flag = FLAG_REINFLATE_CONTENT_VIEW;
+ int flag = FLAG_CONTENT_VIEW_CONTRACTED;
if ((reInflateFlags & flag) != 0) {
- boolean isNewView = !canReapplyRemoteView(result.newContentView, entry.cachedContentView);
+ boolean isNewView =
+ !canReapplyRemoteView(result.newContentView,
+ cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -222,18 +353,19 @@ public class NotificationInflater {
return result.newContentView;
}
};
- applyRemoteView(result, reInflateFlags, flag, row, redactAmbient,
- isNewView, remoteViewClickHandler, callback, entry, privateLayout,
+ applyRemoteView(result, reInflateFlags, flag, cachedContentViews, row, redactAmbient,
+ isNewView, remoteViewClickHandler, callback, privateLayout,
privateLayout.getContractedChild(), privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
}
- flag = FLAG_REINFLATE_EXPANDED_VIEW;
+ flag = FLAG_CONTENT_VIEW_EXPANDED;
if ((reInflateFlags & flag) != 0) {
if (result.newExpandedView != null) {
- boolean isNewView = !canReapplyRemoteView(result.newExpandedView,
- entry.cachedBigContentView);
+ boolean isNewView =
+ !canReapplyRemoteView(result.newExpandedView,
+ cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -245,8 +377,8 @@ public class NotificationInflater {
return result.newExpandedView;
}
};
- applyRemoteView(result, reInflateFlags, flag, row,
- redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ applyRemoteView(result, reInflateFlags, flag, cachedContentViews, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback,
privateLayout, privateLayout.getExpandedChild(),
privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
@@ -254,11 +386,12 @@ public class NotificationInflater {
}
}
- flag = FLAG_REINFLATE_HEADS_UP_VIEW;
+ flag = FLAG_CONTENT_VIEW_HEADS_UP;
if ((reInflateFlags & flag) != 0) {
if (result.newHeadsUpView != null) {
- boolean isNewView = !canReapplyRemoteView(result.newHeadsUpView,
- entry.cachedHeadsUpContentView);
+ boolean isNewView =
+ !canReapplyRemoteView(result.newHeadsUpView,
+ cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -270,19 +403,20 @@ public class NotificationInflater {
return result.newHeadsUpView;
}
};
- applyRemoteView(result, reInflateFlags, flag, row,
- redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ applyRemoteView(result, reInflateFlags, flag, cachedContentViews, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback,
privateLayout, privateLayout.getHeadsUpChild(),
privateLayout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_HEADSUP), runningInflations,
+ VISIBLE_TYPE_HEADSUP), runningInflations,
applyCallback);
}
}
- flag = FLAG_REINFLATE_PUBLIC_VIEW;
+ flag = FLAG_CONTENT_VIEW_PUBLIC;
if ((reInflateFlags & flag) != 0) {
- boolean isNewView = !canReapplyRemoteView(result.newPublicView,
- entry.cachedPublicContentView);
+ boolean isNewView =
+ !canReapplyRemoteView(result.newPublicView,
+ cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -294,18 +428,19 @@ public class NotificationInflater {
return result.newPublicView;
}
};
- applyRemoteView(result, reInflateFlags, flag, row,
- redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ applyRemoteView(result, reInflateFlags, flag, cachedContentViews, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback,
publicLayout, publicLayout.getContractedChild(),
publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
}
- flag = FLAG_REINFLATE_AMBIENT_VIEW;
+ flag = FLAG_CONTENT_VIEW_AMBIENT;
if ((reInflateFlags & flag) != 0) {
NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
- boolean isNewView = !canReapplyAmbient(row, redactAmbient) ||
- !canReapplyRemoteView(result.newAmbientView, entry.cachedAmbientContentView);
+ boolean isNewView = (!canReapplyAmbient(row, redactAmbient)
+ || !canReapplyRemoteView(result.newAmbientView,
+ cachedContentViews.get(FLAG_CONTENT_VIEW_AMBIENT)));
ApplyCallback applyCallback = new ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -317,15 +452,15 @@ public class NotificationInflater {
return result.newAmbientView;
}
};
- applyRemoteView(result, reInflateFlags, flag, row,
- redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+ applyRemoteView(result, reInflateFlags, flag, cachedContentViews, row,
+ redactAmbient, isNewView, remoteViewClickHandler, callback,
newParent, newParent.getAmbientChild(), newParent.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_AMBIENT), runningInflations,
applyCallback);
}
// Let's try to finish, maybe nobody is even inflating anything
- finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+ finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations, callback, row,
redactAmbient);
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(
@@ -335,11 +470,11 @@ public class NotificationInflater {
@VisibleForTesting
static void applyRemoteView(final InflationProgress result,
- final int reInflateFlags, int inflationId,
- final ExpandableNotificationRow row,
- final boolean redactAmbient, boolean isNewView,
+ final @InflationFlag int reInflateFlags, @InflationFlag int inflationId,
+ final ArrayMap<Integer, RemoteViews> cachedContentViews,
+ final ExpandableNotificationRow row, final boolean redactAmbient, boolean isNewView,
RemoteViews.OnClickHandler remoteViewClickHandler,
- @Nullable final InflationCallback callback, NotificationData.Entry entry,
+ @Nullable final InflationCallback callback,
NotificationContentView parentLayout, View existingView,
NotificationViewWrapper existingWrapper,
final HashMap<Integer, CancellationSignal> runningInflations,
@@ -362,7 +497,7 @@ public class NotificationInflater {
existingWrapper.onReinflated();
}
} catch (Exception e) {
- handleInflationError(runningInflations, e, entry.notification, callback);
+ handleInflationError(runningInflations, e, row.getStatusBarNotification(), callback);
// Add a running inflation to make sure we don't trigger callbacks.
// Safe to do because only happens in tests.
runningInflations.put(inflationId, new CancellationSignal());
@@ -381,8 +516,8 @@ public class NotificationInflater {
existingWrapper.onReinflated();
}
runningInflations.remove(inflationId);
- finishIfDone(result, reInflateFlags, runningInflations, callback, row,
- redactAmbient);
+ finishIfDone(result, reInflateFlags, cachedContentViews, runningInflations,
+ callback, row, redactAmbient);
}
@Override
@@ -407,7 +542,8 @@ public class NotificationInflater {
onViewApplied(newView);
} catch (Exception anotherException) {
runningInflations.remove(inflationId);
- handleInflationError(runningInflations, e, entry.notification, callback);
+ handleInflationError(runningInflations, e, row.getStatusBarNotification(),
+ callback);
}
}
};
@@ -430,8 +566,9 @@ public class NotificationInflater {
runningInflations.put(inflationId, cancellationSignal);
}
- private static void handleInflationError(HashMap<Integer, CancellationSignal> runningInflations,
- Exception e, StatusBarNotification notification, @Nullable InflationCallback callback) {
+ private static void handleInflationError(
+ HashMap<Integer, CancellationSignal> runningInflations, Exception e,
+ StatusBarNotification notification, @Nullable InflationCallback callback) {
Assert.isMainThread();
runningInflations.values().forEach(CancellationSignal::cancel);
if (callback != null) {
@@ -444,7 +581,8 @@ public class NotificationInflater {
*
* @return true if the inflation was finished
*/
- private static boolean finishIfDone(InflationProgress result, int reInflateFlags,
+ private static boolean finishIfDone(InflationProgress result,
+ @InflationFlag int reInflateFlags, ArrayMap<Integer, RemoteViews> cachedContentViews,
HashMap<Integer, CancellationSignal> runningInflations,
@Nullable InflationCallback endListener, ExpandableNotificationRow row,
boolean redactAmbient) {
@@ -453,40 +591,40 @@ public class NotificationInflater {
NotificationContentView privateLayout = row.getPrivateLayout();
NotificationContentView publicLayout = row.getPublicLayout();
if (runningInflations.isEmpty()) {
- if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
if (result.inflatedContentView != null) {
privateLayout.setContractedChild(result.inflatedContentView);
}
- entry.cachedContentView = result.newContentView;
+ cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
}
- if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
if (result.inflatedExpandedView != null) {
privateLayout.setExpandedChild(result.inflatedExpandedView);
} else if (result.newExpandedView == null) {
privateLayout.setExpandedChild(null);
}
- entry.cachedBigContentView = result.newExpandedView;
+ cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
row.setExpandable(result.newExpandedView != null);
}
- if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
if (result.inflatedHeadsUpView != null) {
privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
} else if (result.newHeadsUpView == null) {
privateLayout.setHeadsUpChild(null);
}
- entry.cachedHeadsUpContentView = result.newHeadsUpView;
+ cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
}
- if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
if (result.inflatedPublicView != null) {
publicLayout.setContractedChild(result.inflatedPublicView);
}
- entry.cachedPublicContentView = result.newPublicView;
+ cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
}
- if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+ if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
if (result.inflatedAmbientView != null) {
NotificationContentView newParent = redactAmbient
? publicLayout : privateLayout;
@@ -495,12 +633,12 @@ public class NotificationInflater {
newParent.setAmbientChild(result.inflatedAmbientView);
otherParent.setAmbientChild(null);
}
- entry.cachedAmbientContentView = result.newAmbientView;
+ cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
}
entry.headsUpStatusBarText = result.headsUpStatusBarText;
entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
if (endListener != null) {
- endListener.onAsyncInflationFinished(row.getEntry());
+ endListener.onAsyncInflationFinished(row.getEntry(), reInflateFlags);
}
return true;
}
@@ -552,7 +690,15 @@ public class NotificationInflater {
public interface InflationCallback {
void handleInflationException(StatusBarNotification notification, Exception e);
- void onAsyncInflationFinished(NotificationData.Entry entry);
+
+ /**
+ * Callback for after the content views finish inflating.
+ *
+ * @param entry the entry with the content views set
+ * @param inflatedFlags the flags associated with the content views that were inflated
+ */
+ void onAsyncInflationFinished(NotificationData.Entry entry,
+ @InflationFlag int inflatedFlags);
/**
* Used to disable async-ness for tests. Should only be used for tests.
@@ -563,18 +709,13 @@ public class NotificationInflater {
}
public void clearCachesAndReInflate() {
- NotificationData.Entry entry = mRow.getEntry();
- entry.cachedAmbientContentView = null;
- entry.cachedBigContentView = null;
- entry.cachedContentView = null;
- entry.cachedHeadsUpContentView = null;
- entry.cachedPublicContentView = null;
+ mCachedContentViews.clear();
inflateNotificationViews();
}
private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) {
NotificationContentView ambientView = redactAmbient ? row.getPublicLayout()
- : row.getPrivateLayout(); ;
+ : row.getPrivateLayout();
return ambientView.getAmbientChild() != null;
}
@@ -589,7 +730,8 @@ public class NotificationInflater {
private final InflationCallback mCallback;
private final boolean mUsesIncreasedHeadsUpHeight;
private final boolean mRedactAmbient;
- private int mReInflateFlags;
+ private @InflationFlag int mReInflateFlags;
+ private final ArrayMap<Integer, RemoteViews> mCachedContentViews;
private ExpandableNotificationRow mRow;
private Exception mError;
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
@@ -597,15 +739,16 @@ public class NotificationInflater {
private List<Notification.Action> mSmartActions;
private AsyncInflationTask(StatusBarNotification notification,
- int reInflateFlags, ExpandableNotificationRow row, boolean isLowPriority,
- boolean isChildInGroup, boolean usesIncreasedHeight,
+ @InflationFlag int reInflateFlags,
+ ArrayMap<Integer, RemoteViews> cachedContentViews, ExpandableNotificationRow row,
+ boolean isLowPriority, boolean isChildInGroup, boolean usesIncreasedHeight,
boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
- InflationCallback callback,
- RemoteViews.OnClickHandler remoteViewClickHandler,
+ InflationCallback callback, RemoteViews.OnClickHandler remoteViewClickHandler,
List<Notification.Action> smartActions) {
mRow = row;
mSbn = notification;
mReInflateFlags = reInflateFlags;
+ mCachedContentViews = cachedContentViews;
mContext = mRow.getContext();
mIsLowPriority = isLowPriority;
mIsChildInGroup = isChildInGroup;
@@ -622,6 +765,7 @@ public class NotificationInflater {
}
@VisibleForTesting
+ @InflationFlag
public int getReInflateFlags() {
return mReInflateFlags;
}
@@ -642,10 +786,9 @@ public class NotificationInflater {
packageContext);
processor.processNotification(notification, recoveredBuilder);
}
- return createRemoteViews(mReInflateFlags,
- recoveredBuilder, mIsLowPriority, mIsChildInGroup,
- mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
- packageContext);
+ return createRemoteViews(mReInflateFlags, recoveredBuilder, mIsLowPriority,
+ mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
+ mRedactAmbient, packageContext);
} catch (Exception e) {
mError = e;
return null;
@@ -655,8 +798,8 @@ public class NotificationInflater {
@Override
protected void onPostExecute(InflationProgress result) {
if (mError == null) {
- mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient,
- mRemoteViewClickHandler, this);
+ mCancellationSignal = apply(result, mReInflateFlags, mCachedContentViews, mRow,
+ mRedactAmbient, mRemoteViewClickHandler, this);
} else {
handleError(mError);
}
@@ -706,10 +849,11 @@ public class NotificationInflater {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @InflationFlag int inflatedFlags) {
mRow.getEntry().onInflationTaskFinished();
mRow.onNotificationUpdated();
- mCallback.onAsyncInflationFinished(mRow.getEntry());
+ mCallback.onAsyncInflationFinished(mRow.getEntry(), inflatedFlags);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 2ca7282041cc..f76284dd1ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.row.wrapper;
import android.content.Context;
+import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.NotificationHeaderView;
@@ -76,8 +77,11 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
Drawable background = mView.getBackground();
if (background instanceof ColorDrawable) {
- mBackgroundColor = ((ColorDrawable) background).getColor();
- mView.setBackground(null);
+ int backgroundColor = ((ColorDrawable) background).getColor();
+ if (backgroundColor != Color.TRANSPARENT) {
+ mBackgroundColor = backgroundColor;
+ mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
+ }
}
}
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 9ddab7cc0b2f..33ac390de29f 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
@@ -4849,7 +4849,7 @@ public class NotificationStackScrollLayout extends ViewGroup
activatedChild.makeInactive(false /* animate */);
}
updateFooter();
- updateChildren();
+ requestChildrenUpdate();
onUpdateRowStates();
mEntryManager.updateNotifications();
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 9acaf21c41f5..c66bbb1696ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -48,6 +48,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final NotificationStackScrollLayout mStackScroller;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mClockView;
+ private final View mOperatorNameView;
private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelView mPanelView;
private final Consumer<ExpandableNotificationRow>
@@ -65,8 +66,10 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> updatePanelTranslation();
+ private boolean mAnimationsEnabled = true;
Point mPoint;
+
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
@@ -75,7 +78,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
statusbarView.findViewById(R.id.heads_up_status_bar_view),
statusbarView.findViewById(R.id.notification_stack_scroller),
statusbarView.findViewById(R.id.notification_panel),
- statusbarView.findViewById(R.id.clock));
+ statusbarView.findViewById(R.id.clock),
+ statusbarView.findViewById(R.id.operator_name_frame));
}
@VisibleForTesting
@@ -85,7 +89,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
HeadsUpStatusBarView headsUpStatusBarView,
NotificationStackScrollLayout stackScroller,
NotificationPanelView panelView,
- View clockView) {
+ View clockView,
+ View operatorNameView) {
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(this);
@@ -101,6 +106,7 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
+ mOperatorNameView = operatorNameView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mDarkIconDispatcher.addDarkReceiver(this);
@@ -230,20 +236,52 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mShown = isShown;
if (isShown) {
mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
- CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+ show(mHeadsUpStatusBarView);
+ hide(mClockView, View.INVISIBLE);
+ if (mOperatorNameView != null) {
+ hide(mOperatorNameView, View.INVISIBLE);
+ }
} else {
- CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+ show(mClockView);
+ if (mOperatorNameView != null) {
+ show(mOperatorNameView);
+ }
+ hide(mHeadsUpStatusBarView, View.GONE);
}
}
}
+ /**
+ * Hides the view and sets the state to endState when finished.
+ *
+ * @param view The view to hide.
+ * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+ * @see View#setVisibility(int)
+ *
+ */
+ private void hide(View view, int endState) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+ 0 /* delay */, () -> view.setVisibility(endState));
+ } else {
+ view.setVisibility(endState);
+ }
+ }
+
+ private void show(View view) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ } else {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @VisibleForTesting
+ void setAnimationsEnabled(boolean enabled) {
+ mAnimationsEnabled = enabled;
+ }
+
@VisibleForTesting
public boolean isShown() {
return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 538a260b4b8e..072343a8b101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -560,7 +560,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
return;
}
mDarkAmount = darkAmount;
- mIndicationArea.setAlpha(1f - darkAmount);
+ mIndicationController.setDarkAmount(darkAmount);
+ mLockIcon.setDarkAmount(darkAmount);
}
private static boolean isSuccessfulLaunch(int result) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2a4595b980ac..8ac867727e65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -361,6 +361,8 @@ public class KeyguardBouncer {
} else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
onFullyHidden();
mExpansionCallback.onFullyHidden();
+ } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
+ mExpansionCallback.onStartingToHide();
}
}
@@ -481,6 +483,7 @@ public class KeyguardBouncer {
public interface BouncerExpansionCallback {
void onFullyShown();
+ void onStartingToHide();
void onFullyHidden();
}
}
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 7c84df91fffa..e85ff8ef22c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -519,7 +519,14 @@ public class KeyguardStatusBarView extends RelativeLayout
mStatusIconContainer.setAlpha(alpha);
mStatusIconContainer.setVisibility(visibility);
- mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+ float iconsX = -mCurrentBurnInOffsetX;
+ if (mMultiUserSwitch.getVisibility() == VISIBLE) {
+ // Squared alpha to add a nice easing curve and avoid overlap during animation.
+ mMultiUserAvatar.setAlpha(alpha * alpha);
+ iconsX += mMultiUserAvatar.getPaddingLeft() + mMultiUserAvatar.getWidth()
+ + mMultiUserAvatar.getPaddingRight();
+ }
+ mSystemIconsContainer.setTranslationX(iconsX * mDarkAmount);
mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
updateIconsAndTextColors();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 2edc294084cd..d5067b5c7e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -18,13 +18,14 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
-import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.graphics.ColorUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -58,6 +59,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
private int mDensity;
private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
+ private float mDarkAmount;
public LockIcon(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -130,6 +132,7 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
? (AnimatedVectorDrawable) icon
: null;
setImageDrawable(icon, false);
+ updateDarkTint();
if (mHasFaceUnlockIcon) {
announceForAccessibility(getContext().getString(
R.string.accessibility_scanning_face));
@@ -259,4 +262,15 @@ public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChange
return STATE_LOCKED;
}
}
+
+ public void setDarkAmount(float darkAmount) {
+ mDarkAmount = darkAmount;
+ updateDarkTint();
+ }
+
+ private void updateDarkTint() {
+ Drawable drawable = getDrawable().mutate();
+ int color = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, mDarkAmount);
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ }
}
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 0b5871ed5e3f..99a2cdc9a545 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -236,7 +236,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
try {
WindowManagerGlobal.getWindowManagerService()
- .watchRotation(mRotationWatcher, getContext().getDisplay().getDisplayId());
+ .watchRotation(mRotationWatcher, getContext().getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -641,9 +641,12 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
// Injected from StatusBar at creation.
public void setCurrentSysuiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
- mNavigationBarMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
+ final int barMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
View.NAVIGATION_BAR_TRANSPARENT);
+ if (barMode != -1) {
+ mNavigationBarMode = barMode;
+ }
checkNavBarModes();
mStatusBar.touchAutoHide();
mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
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 c4efa9431317..980ba8751df4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1100,10 +1100,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
visibilityToString(getCurrentView().getVisibility()),
getCurrentView().getAlpha()));
- pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
+ pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s darkIntensity=%.2f",
mDisabledFlags,
mVertical ? "true" : "false",
- getMenuButton().isVisible() ? "true" : "false"));
+ getMenuButton().isVisible() ? "true" : "false",
+ getLightTransitionsController().getCurrentDarkIntensity()));
dumpButton(pw, "back", getBackButton());
dumpButton(pw, "home", getHomeButton());
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 a7c43cdbf9c5..3bdd60130de3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -524,6 +524,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mIsOccluded;
private boolean mWereIconsJustHidden;
private boolean mBouncerWasShowingWhenHidden;
+ private boolean mIsCollapsingToShowActivityOverLockscreen;
// Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
// this animation is tied to the scrim for historic reasons.
@@ -2232,7 +2233,11 @@ public class StatusBar extends SystemUI implements DemoMode,
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
- showBouncerIfKeyguard();
+ if (!mIsCollapsingToShowActivityOverLockscreen) {
+ showBouncerIfKeyguard();
+ } else if (DEBUG) {
+ Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
+ }
recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
@@ -3751,9 +3756,6 @@ public class StatusBar extends SystemUI implements DemoMode,
Trace.beginSection("StatusBar#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
- boolean dozingAnimated = mDozingRequested
- && DozeParameters.getInstance(mContext).shouldControlScreenOff();
- mNotificationPanel.resetViews(dozingAnimated);
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.setKeyguard(true,
mStatusBarStateController.fromShadeLocked());
@@ -3785,6 +3787,47 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
+ public void onDozingChanged(boolean isDozing) {
+ Trace.beginSection("StatusBar#updateDozing");
+ mDozing = isDozing;
+
+ // Collapse the notification panel if open
+ boolean dozingAnimated = mDozingRequested
+ && DozeParameters.getInstance(mContext).shouldControlScreenOff();
+ mNotificationPanel.resetViews(dozingAnimated);
+
+ mKeyguardViewMediator.setAodShowing(mDozing);
+
+ //TODO: make these folks listeners of StatusBarStateController.onDozingChanged
+ mStatusBarWindowController.setDozing(mDozing);
+ mStatusBarKeyguardViewManager.setDozing(mDozing);
+ if (mAmbientIndicationContainer instanceof DozeReceiver) {
+ ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
+ }
+
+ mEntryManager.updateNotifications();
+ updateDozingState();
+ updateScrimController();
+ updateReportRejectedTouchVisibility();
+ Trace.endSection();
+ }
+
+ private void updateDozing() {
+ // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
+ boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
+ || mBiometricUnlockController.getMode()
+ == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+ // When in wake-and-unlock we may not have received a change to mState
+ // but we still should not be dozing, manually set to false.
+ if (mBiometricUnlockController.getMode() ==
+ BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
+ dozing = false;
+ }
+
+ mStatusBarStateController.setIsDozing(dozing);
+ }
+
+ @Override
public void onActivationReset(ActivatableNotificationView view) {
if (view == mNotificationPanel.getActivatedChild()) {
mNotificationPanel.setActivatedChild(null);
@@ -4336,34 +4379,6 @@ public class StatusBar extends SystemUI implements DemoMode,
updateScrimController();
}
- private void updateDozing() {
- Trace.beginSection("StatusBar#updateDozing");
- // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
- boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
- || mBiometricUnlockController.getMode()
- == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
- // When in wake-and-unlock we may not have received a change to mState
- // but we still should not be dozing, manually set to false.
- if (mBiometricUnlockController.getMode() ==
- mBiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
- dozing = false;
- }
- if (mDozing != dozing) {
- mDozing = dozing;
- mKeyguardViewMediator.setAodShowing(mDozing);
- mStatusBarWindowController.setDozing(mDozing);
- mStatusBarKeyguardViewManager.setDozing(mDozing);
- if (mAmbientIndicationContainer instanceof DozeReceiver) {
- ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
- }
- mEntryManager.updateNotifications();
- updateDozingState();
- updateScrimController();
- updateReportRejectedTouchVisibility();
- }
- Trace.endSection();
- }
-
@VisibleForTesting
void updateScrimController() {
Trace.beginSection("StatusBar#updateScrimController");
@@ -4745,7 +4760,11 @@ public class StatusBar extends SystemUI implements DemoMode,
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mLockscreenUserManager.getCurrentUserId());
final boolean wasOccluded = mIsOccluded;
- dismissKeyguardThenExecute(() -> {
+ boolean showOverLockscreen = mStatusBarKeyguardViewManager.isShowing()
+ && PreviewInflater.wouldShowOverLockscreen(mContext,
+ intent.getIntent(),
+ mLockscreenUserManager.getCurrentUserId());
+ OnDismissAction postKeyguardAction = () -> {
// TODO: Some of this code may be able to move to NotificationEntryManager.
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
// Release the HUN notification to the shade.
@@ -4853,9 +4872,14 @@ public class StatusBar extends SystemUI implements DemoMode,
// Automatically remove all notifications that we may have kept around longer
removeNotification(sbn);
}
+
+ mIsCollapsingToShowActivityOverLockscreen = false;
};
- if (mStatusBarKeyguardViewManager.isShowing()
+ if (showOverLockscreen) {
+ addPostCollapseAction(runnable);
+ collapsePanel(true /* animate */);
+ } else if (mStatusBarKeyguardViewManager.isShowing()
&& mStatusBarKeyguardViewManager.isOccluded()) {
mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
collapsePanel(true /* animate */);
@@ -4864,7 +4888,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
return !mNotificationPanel.isFullyCollapsed();
- }, afterKeyguardGone);
+ };
+ if (showOverLockscreen) {
+ mIsCollapsingToShowActivityOverLockscreen = true;
+ postKeyguardAction.onDismiss();
+ } else {
+ dismissKeyguardThenExecute(postKeyguardAction, afterKeyguardGone);
+ }
}
private void collapseOnMainThread() {
@@ -4881,7 +4911,10 @@ public class StatusBar extends SystemUI implements DemoMode,
public void collapsePanel(boolean animate) {
if (animate) {
- collapsePanel();
+ boolean willCollapse = collapsePanel();
+ if (!willCollapse) {
+ runPostCollapseRunnables();
+ }
} else if (!isPresenterFullyCollapsed()) {
instantCollapseNotificationPanel();
visibilityChanged(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 3db1456446a0..ac3608bc622a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,6 +84,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
@Override
+ public void onStartingToHide() {
+ updateStates();
+ }
+
+ @Override
public void onFullyHidden() {
updateStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 57c7e285e29f..0d37b550d4e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -173,9 +173,9 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
}
if (state.dozing) {
- mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+ mLpChanged.privateFlags |= LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
} else {
- mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+ mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index d477587f8ecb..b4d24d16113e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -151,6 +153,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, false);
}
+ entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
}
protected void updatePinnedMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 687b83a4bf63..92034b2be0ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -146,6 +146,14 @@ public class PreviewInflater {
== null;
}
+ public static boolean wouldShowOverLockscreen(Context ctx, Intent intent, int currentUserId) {
+ ActivityInfo targetActivityInfo = getTargetActivityInfo(ctx, intent, currentUserId,
+ false /* onlyDirectBootAware */);
+ return targetActivityInfo != null
+ && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED
+ | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0;
+ }
+
/**
* @param onlyDirectBootAware a boolean indicating whether the matched activity packages must
* be direct boot aware when in direct boot mode if false, all
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
index af99236cc393..e85dee841715 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunablePadding.java
@@ -51,7 +51,9 @@ public class TunablePadding implements Tunable {
public void onTuningChanged(String key, String newValue) {
int dimen = mDefaultSize;
if (newValue != null) {
- dimen = (int) (Integer.parseInt(newValue) * mDensity);
+ try {
+ dimen = (int) (Integer.parseInt(newValue) * mDensity);
+ } catch (NumberFormatException ex) {}
}
int left = mView.isLayoutRtl() ? FLAG_END : FLAG_START;
int right = mView.isLayoutRtl() ? FLAG_START : FLAG_END;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 66d5ee1a276f..4102e63f7330 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -54,7 +54,7 @@ public class UsbDebuggingActivity extends AlertActivity
@Override
public void onCreate(Bundle icicle) {
Window window = getWindow();
- window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ window.addSystemFlags(WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
super.onCreate(icicle);
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
index 5790ba36ac5c..0dd8937de80e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.util;
+import android.content.Context;
import android.hardware.HardwareBuffer;
import android.hardware.Sensor;
import android.hardware.SensorAdditionalInfo;
@@ -30,7 +31,11 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.shared.plugins.PluginManager;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -40,7 +45,8 @@ import java.util.List;
* without blocking. Note that this means registering listeners now always appears successful even
* if it is not.
*/
-public class AsyncSensorManager extends SensorManager {
+public class AsyncSensorManager extends SensorManager
+ implements PluginListener<SensorManagerPlugin> {
private static final String TAG = "AsyncSensorManager";
@@ -48,12 +54,15 @@ public class AsyncSensorManager extends SensorManager {
private final List<Sensor> mSensorCache;
private final HandlerThread mHandlerThread = new HandlerThread("async_sensor");
@VisibleForTesting final Handler mHandler;
+ private final List<SensorManagerPlugin> mPlugins;
- public AsyncSensorManager(SensorManager inner) {
+ public AsyncSensorManager(SensorManager inner, PluginManager pluginManager) {
mInner = inner;
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL);
+ mPlugins = new ArrayList<>();
+ pluginManager.addPluginListener(this, SensorManagerPlugin.class, true /* allowMultiple */);
}
@Override
@@ -63,7 +72,7 @@ public class AsyncSensorManager extends SensorManager {
@Override
protected List<Sensor> getFullDynamicSensorList() {
- return mInner.getDynamicSensorList(Sensor.TYPE_ALL);
+ return mInner.getSensorList(Sensor.TYPE_ALL);
}
@Override
@@ -132,6 +141,32 @@ public class AsyncSensorManager extends SensorManager {
return true;
}
+ /**
+ * Requests for all sensors that match the given type from all plugins.
+ * @param sensor
+ * @param listener
+ */
+ public void requestPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
+ SensorManagerPlugin.TriggerEventListener listener) {
+ if (mPlugins.isEmpty()) {
+ Log.w(TAG, "No plugins registered");
+ }
+ mHandler.post(() -> {
+ for (int i = 0; i < mPlugins.size(); i++) {
+ mPlugins.get(i).registerTriggerEvent(sensor, listener);
+ }
+ });
+ }
+
+ public void cancelPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
+ SensorManagerPlugin.TriggerEventListener listener) {
+ mHandler.post(() -> {
+ for (int i = 0; i < mPlugins.size(); i++) {
+ mPlugins.get(i).unregisterTriggerEvent(sensor, listener);
+ }
+ });
+ }
+
@Override
protected boolean initDataInjectionImpl(boolean enable) {
throw new UnsupportedOperationException("not implemented");
@@ -159,4 +194,14 @@ public class AsyncSensorManager extends SensorManager {
}
});
}
+
+ @Override
+ public void onPluginConnected(SensorManagerPlugin plugin, Context pluginContext) {
+ mPlugins.add(plugin);
+ }
+
+ @Override
+ public void onPluginDisconnected(SensorManagerPlugin plugin) {
+ mPlugins.remove(plugin);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 4810b0b91c10..7abac0054e5d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -556,14 +556,15 @@ public class VolumeDialogImpl implements VolumeDialog {
mHandler.removeMessages(H.SHOW);
mHandler.removeMessages(H.DISMISS);
rescheduleTimeoutH();
- mShowing = true;
if (mConfigChanged) {
- initDialog();
+ initDialog(); // resets mShowing to false
mConfigurableTexts.update();
mConfigChanged = false;
}
+
initSettingsH();
+ mShowing = true;
mDialog.show();
Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
mController.notifyVisible(true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
index cfe981890bbf..ab3a3e126b34 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
@@ -46,9 +46,9 @@ class KeyguardPatternViewTest : SysuiTestCase() {
}
@Test
- fun onResume_clearsTextField() {
+ fun onPause_clearsTextField() {
mSecurityMessage.setMessage("an old message")
- mKeyguardPatternView.onResume(KeyguardSecurityView.SCREEN_ON)
+ mKeyguardPatternView.onPause()
assertThat(mSecurityMessage.text).isEqualTo("")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
new file mode 100644
index 000000000000..d9412ecd9a3a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.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.qs.tiles;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quicksettings.Tile;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+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.HashSet;
+import java.util.Set;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CastTileTest extends SysuiTestCase {
+
+ @Mock
+ private CastController mController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private KeyguardMonitor mKeyguard;
+ @Mock
+ private NetworkController mNetworkController;
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ NetworkController.SignalCallback mCallback;
+
+ private TestableLooper mTestableLooper;
+ private CastTile mCastTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mController = mDependency.injectMockDependency(CastController.class);
+ mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+ mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
+ mNetworkController = mDependency.injectMockDependency(NetworkController.class);
+
+ when(mHost.getContext()).thenReturn(mContext);
+
+ mCastTile = new CastTile(mHost);
+
+ // We are not setting the mocks to listening, so we trigger a first refresh state to
+ // set the initial state
+ mCastTile.refreshState();
+
+ mCastTile.handleSetListening(true);
+ ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
+ verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
+ mCallback = signalCallbackArgumentCaptor.getValue();
+
+ }
+
+ @Test
+ public void testStateUnavailable_wifiDisabled() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateUnavailable_wifiNotConnected() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateActive_wifiEnabledAndCasting() {
+ CastController.CastDevice device = mock(CastController.CastDevice.class);
+ device.state = CastController.CastDevice.STATE_CONNECTED;
+ Set<CastController.CastDevice> devices = new HashSet<>();
+ devices.add(device);
+ when(mController.getCastDevices()).thenReturn(devices);
+
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateInactive_wifiEnabledNotCasting() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index bdd05c7e6384..aae6d93cebed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
@@ -28,6 +30,7 @@ import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.Context;
+import android.graphics.Color;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -45,6 +48,8 @@ import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -54,9 +59,13 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private String mDisclosureWithOrganization;
- private DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
- private ViewGroup mIndicationArea = mock(ViewGroup.class);
- private KeyguardIndicationTextView mDisclosure = mock(KeyguardIndicationTextView.class);
+ @Mock
+ private DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ private ViewGroup mIndicationArea;
+ @Mock
+ private KeyguardIndicationTextView mDisclosure;
+ private KeyguardIndicationTextView mTextView;
private KeyguardIndicationController mController;
private WakeLockFake mWakeLock;
@@ -64,7 +73,9 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTextView = new KeyguardIndicationTextView(mContext);
mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
@@ -74,6 +85,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
.thenReturn(mDisclosure);
+ when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
mWakeLock = new WakeLockFake();
}
@@ -189,4 +201,17 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
});
assertFalse("WakeLock expected: RELEASED, was: HELD", held[0]);
}
+
+ @Test
+ public void transientIndication_visibleWhenDozing() {
+ createController();
+
+ mController.setVisible(true);
+ mController.showTransientIndication("Test");
+ mController.setDozing(true);
+
+ assertThat(mTextView.getText()).isEqualTo("Test");
+ assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE);
+ assertThat(mTextView.getAlpha()).isEqualTo(1f);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index edf29ac1c4f8..aca1f90b5aa8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -31,9 +31,9 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -67,16 +67,50 @@ public class NotificationTestHelper {
mGroupManager.setHeadsUpManager(mHeadsUpManager);
}
+ /**
+ * Creates a generic row.
+ *
+ * @return a generic row with no special properties.
+ * @throws Exception
+ */
public ExpandableNotificationRow createRow() throws Exception {
return createRow(PKG, UID);
}
+ /**
+ * Create a row with the package and user id specified.
+ *
+ * @param pkg package
+ * @param uid user id
+ * @return a row with a notification using the package and user id
+ * @throws Exception
+ */
public ExpandableNotificationRow createRow(String pkg, int uid) throws Exception {
return createRow(pkg, uid, false /* isGroupSummary */, null /* groupKey */);
}
+ /**
+ * Creates a row based off the notification given.
+ *
+ * @param notification the notification
+ * @return a row built off the notification
+ * @throws Exception
+ */
public ExpandableNotificationRow createRow(Notification notification) throws Exception {
- return generateRow(notification, PKG, UID, false /* isGroupRow */);
+ return generateRow(notification, PKG, UID, 0 /* extraInflationFlags */);
+ }
+
+ /**
+ * Create a row with the specified content views inflated in addition to the default.
+ *
+ * @param extraInflationFlags the flags corresponding to the additional content views that
+ * should be inflated
+ * @return a row with the specified content views inflated in addition to the default
+ * @throws Exception
+ */
+ public ExpandableNotificationRow createRow(@InflationFlag int extraInflationFlags)
+ throws Exception {
+ return generateRow(createNotification(), PKG, UID, extraInflationFlags);
}
/**
@@ -122,34 +156,53 @@ public class NotificationTestHelper {
boolean isGroupSummary,
@Nullable String groupKey)
throws Exception {
+ Notification notif = createNotification(isGroupSummary, groupKey);
+ return generateRow(notif, pkg, uid, 0 /* inflationFlags */);
+ }
+
+ /**
+ * Creates a generic notification.
+ *
+ * @return a notification with no special properties
+ */
+ private Notification createNotification() {
+ return createNotification(false /* isGroupSummary */, null /* groupKey */);
+ }
+
+ /**
+ * Creates a notification with the given parameters.
+ *
+ * @param isGroupSummary whether the notification is a group summary
+ * @param groupKey the group key for the notification group used across notifications
+ * @return a notification that is in the group specified or standalone if unspecified
+ */
+ private Notification createNotification(boolean isGroupSummary,
+ @Nullable String groupKey) {
Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
R.drawable.ic_person)
.setCustomContentView(new RemoteViews(mContext.getPackageName(),
R.layout.custom_view_dark))
.build();
- Notification.Builder notificationBuilder =
- new Notification.Builder(mContext, "channelId")
- .setSmallIcon(R.drawable.ic_person)
- .setContentTitle("Title")
- .setContentText("Text")
- .setPublicVersion(publicVersion);
-
- // Group notification setup
+ Notification.Builder notificationBuilder = new Notification.Builder(mContext, "channelId")
+ .setSmallIcon(R.drawable.ic_person)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .setPublicVersion(publicVersion)
+ .setStyle(new Notification.BigTextStyle().bigText("Big Text"));
if (isGroupSummary) {
notificationBuilder.setGroupSummary(true);
}
if (!TextUtils.isEmpty(groupKey)) {
notificationBuilder.setGroup(groupKey);
}
-
- return generateRow(notificationBuilder.build(), pkg, uid, !TextUtils.isEmpty(groupKey));
+ return notificationBuilder.build();
}
private ExpandableNotificationRow generateRow(
Notification notification,
String pkg,
int uid,
- boolean isGroupRow)
+ @InflationFlag int extraInflationFlags)
throws Exception {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
mContext.LAYOUT_INFLATER_SERVICE);
@@ -179,8 +232,10 @@ public class NotificationTestHelper {
entry.channel = new NotificationChannel(
notification.getChannelId(), notification.getChannelId(), IMPORTANCE_DEFAULT);
entry.channel.setBlockableSystem(true);
+ row.setEntry(entry);
+ row.getNotificationInflater().addInflationFlags(extraInflationFlags);
NotificationInflaterTest.runThenWaitForInflation(
- () -> row.updateNotification(entry),
+ () -> row.inflateViews(),
row.getNotificationInflater());
// This would be done as part of onAsyncInflationFinished, but we skip large amounts of
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 4e16b7f94283..f01ae7a23533 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
@@ -68,6 +68,7 @@ import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
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.RowInflaterTask;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -134,8 +135,9 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
- super.onAsyncInflationFinished(entry);
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @NotificationInflater.InflationFlag int inflatedFlags) {
+ super.onAsyncInflationFinished(entry, inflatedFlags);
mCountDownLatch.countDown();
}
@@ -428,7 +430,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow).updateNotification(eq(mEntry));
+ verify(mRow).setEntry(eq(mEntry));
assertEquals(1, mEntry.smartActions.size());
assertEquals("action", mEntry.smartActions.get(0).title);
}
@@ -443,7 +445,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.key, null);
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).updateNotification(eq(mEntry));
+ verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(0, mEntry.smartActions.size());
}
@@ -457,7 +459,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).updateNotification(eq(mEntry));
+ verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.smartActions.size());
assertEquals("action", mEntry.smartActions.get(0).title);
}
@@ -472,7 +474,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
setSmartActions(mEntry.key, new ArrayList<>(Arrays.asList(createAction())));
mEntryManager.updateNotificationRanking(mRankingMap);
- verify(mRow, never()).updateNotification(eq(mEntry));
+ verify(mRow, never()).setEntry(eq(mEntry));
assertEquals(1, mEntry.smartActions.size());
assertEquals("action", mEntry.smartActions.get(0).title);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 743b307d0666..cfc75261123a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -18,8 +18,13 @@ package com.android.systemui.statusbar.notification.row;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -35,6 +40,7 @@ import android.app.AppOpsManager;
import android.app.NotificationChannel;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
@@ -134,6 +140,15 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
}
@Test
+ public void testFreeContentViewWhenSafe() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
+
+ row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
+
+ assertNull(row.getPrivateLayout().getHeadsUpChild());
+ }
+
+ @Test
public void testAboveShelfChangedListenerCalled() throws Exception {
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
index 81e79d1490b9..150d9337d4a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
@@ -16,10 +16,13 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_ALL;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_EXPANDED;
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_REINFLATE_ALL;
-
-import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -34,6 +37,7 @@ import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
@@ -82,7 +86,8 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @NotificationInflater.InflationFlag int inflatedFlags) {
}
});
}
@@ -91,7 +96,7 @@ public class NotificationInflaterTest extends SysuiTestCase {
public void testIncreasedHeadsUpBeingUsed() {
mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
+ mNotificationInflater.inflateNotificationViews(FLAG_CONTENT_VIEW_ALL, builder, mContext);
verify(builder).createHeadsUpContentView(true);
}
@@ -99,7 +104,7 @@ public class NotificationInflaterTest extends SysuiTestCase {
public void testIncreasedHeightBeingUsed() {
mNotificationInflater.setUsesIncreasedHeight(true);
Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
+ mNotificationInflater.inflateNotificationViews(FLAG_CONTENT_VIEW_ALL, builder, mContext);
verify(builder).createContentView(true);
}
@@ -111,14 +116,14 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Test
- public void testInflationCallsOnlyRightMethod() throws Exception {
- mRow.getPrivateLayout().removeAllViews();
- mRow.getEntry().cachedBigContentView = null;
- runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(
- FLAG_REINFLATE_EXPANDED_VIEW), mNotificationInflater);
- assertTrue(mRow.getPrivateLayout().getChildCount() == 1);
- assertTrue(mRow.getPrivateLayout().getChildAt(0)
- == mRow.getPrivateLayout().getExpandedChild());
+ public void testInflationOnlyInflatesSetFlags() throws Exception {
+ mNotificationInflater.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP,
+ true /* shouldInflate */);
+ runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
+ mNotificationInflater);
+
+ assertNotNull(mRow.getPrivateLayout().getHeadsUpChild());
+ assertNull(mRow.getShowingLayout().getAmbientChild());
verify(mRow).onNotificationUpdated();
}
@@ -155,8 +160,9 @@ public class NotificationInflaterTest extends SysuiTestCase {
new NotificationInflater.InflationProgress();
result.packageContext = mContext;
CountDownLatch countDownLatch = new CountDownLatch(1);
- NotificationInflater.applyRemoteView(result, FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow,
- false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(),
+ NotificationInflater.applyRemoteView(result, FLAG_CONTENT_VIEW_EXPANDED, 0,
+ new ArrayMap() /* cachedContentViews */, mRow, false /* redactAmbient */,
+ true /* isNewView */, new RemoteViews.OnClickHandler(),
new NotificationInflater.InflationCallback() {
@Override
public void handleInflationException(StatusBarNotification notification,
@@ -166,10 +172,11 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @NotificationInflater.InflationFlag int inflatedFlags) {
countDownLatch.countDown();
}
- }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(),
+ }, mRow.getPrivateLayout(), null, null, new HashMap<>(),
new NotificationInflater.ApplyCallback() {
@Override
public void setResultView(View v) {
@@ -186,16 +193,19 @@ public class NotificationInflaterTest extends SysuiTestCase {
/* Cancelling requires us to be on the UI thread otherwise we might have a race */
@Test
- public void testSupersedesExistingTask() throws Exception {
+ public void testSupersedesExistingTask() {
+ mNotificationInflater.addInflationFlags(FLAG_CONTENT_VIEW_ALL);
mNotificationInflater.inflateNotificationViews();
+
+ // Trigger inflation of content and expanded only.
mNotificationInflater.setIsLowPriority(true);
mNotificationInflater.setIsChildInGroup(true);
+
InflationTask runningTask = mRow.getEntry().getRunningTask();
NotificationInflater.AsyncInflationTask asyncInflationTask =
(NotificationInflater.AsyncInflationTask) runningTask;
- Assert.assertSame("Successive inflations don't inherit the previous flags!",
- asyncInflationTask.getReInflateFlags(),
- NotificationInflater.FLAG_REINFLATE_ALL);
+ assertEquals("Successive inflations don't inherit the previous flags!",
+ asyncInflationTask.getReInflateFlags(), FLAG_CONTENT_VIEW_ALL);
runningTask.abort();
}
@@ -231,7 +241,8 @@ public class NotificationInflaterTest extends SysuiTestCase {
}
@Override
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
+ public void onAsyncInflationFinished(NotificationData.Entry entry,
+ @NotificationInflater.InflationFlag int inflatedFlags) {
if (expectingException) {
exceptionHolder.setException(new RuntimeException(
"Inflation finished even though there should be an error"));
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 a4004ae2d7cc..10b0d834b36b 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
@@ -54,6 +54,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
private HeadsUpManagerPhone mHeadsUpManager;
+ private View mOperatorNameView;
@Before
public void setUp() throws Exception {
@@ -63,13 +64,15 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+ mOperatorNameView = new View(mContext);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
mHeadsUpManager,
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
- new View(mContext));
+ new View(mContext),
+ mOperatorNameView);
mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
}
@@ -116,6 +119,22 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
}
@Test
+ public void testOperatorNameViewUpdated() {
+ mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+ }
+
+ @Test
public void testHeaderReadFromOldController() {
mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f);
@@ -125,6 +144,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
+ new View(mContext),
new View(mContext));
newController.readFrom(mHeadsUpAppearanceController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index a7954f2aa199..020682b6b4e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -170,13 +170,17 @@ public class KeyguardBouncerTest extends SysuiTestCase {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
- mBouncer.setExpansion(1);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
verify(mFalsingManager).onBouncerHidden();
verify(mExpansionCallback).onFullyHidden();
- mBouncer.setExpansion(0);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
verify(mFalsingManager).onBouncerShown();
verify(mExpansionCallback).onFullyShown();
+
+ verify(mExpansionCallback, never()).onStartingToHide();
+ mBouncer.setExpansion(0.9f);
+ verify(mExpansionCallback).onStartingToHide();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index f7a7e0430977..de26c709922d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -74,14 +74,14 @@ public class StatusBarWindowControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(WindowManager.LayoutParams.class);
verify(mWindowManager).updateViewLayout(any(), captor.capture());
int flag = captor.getValue().privateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+ & WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
assertThat(flag).isNotEqualTo(0);
reset(mWindowManager);
mStatusBarWindowController.setDozing(false);
verify(mWindowManager).updateViewLayout(any(), captor.capture());
flag = captor.getValue().privateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+ & WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
assertThat(flag).isEqualTo(0);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
index 469bdc0918d9..77df7919ed29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.util;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -28,6 +29,8 @@ import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.utils.hardware.FakeSensorManager;
import org.junit.Before;
@@ -42,9 +45,11 @@ public class AsyncSensorManagerTest extends SysuiTestCase {
private FakeSensorManager mFakeSensorManager;
private SensorEventListener mListener;
private FakeSensorManager.MockProximitySensor mSensor;
+ private PluginManager mPluginManager;
@Before
public void setUp() throws Exception {
+ mPluginManager = mock(PluginManager.class);
mFakeSensorManager = new FakeSensorManager(mContext);
mAsyncSensorManager = new TestableAsyncSensorManager(mFakeSensorManager);
mSensor = mFakeSensorManager.getMockProximitySensor();
@@ -86,9 +91,15 @@ public class AsyncSensorManagerTest extends SysuiTestCase {
verifyNoMoreInteractions(mListener);
}
+ @Test
+ public void registersPlugin_whenLoaded() {
+ verify(mPluginManager).addPluginListener(eq(mAsyncSensorManager),
+ eq(SensorManagerPlugin.class), eq(true) /* allowMultiple */);
+ }
+
private class TestableAsyncSensorManager extends AsyncSensorManager {
public TestableAsyncSensorManager(SensorManager sensorManager) {
- super(sensorManager);
+ super(sensorManager, mPluginManager);
}
public void waitUntilRequestsCompleted() {
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5e87707c39e6..d86de5dfd799 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6549,6 +6549,21 @@ message MetricsEvent {
// Subtype: The importance of a notification has been changed
ADJUSTMENT_KEY_IMPORTANCE = 1580;
+ // OPEN: Settings > Network & internet > Mobile network > Choose network
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_NETWORK_SELECT = 1581;
+
+ // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_DATA_DIALOG = 1582;
+
+ // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_ROAMING_DIALOG = 1583;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6918275dd8c0..fbceade2341f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2630,7 +2630,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final List<Integer> outsideWindowsIds;
final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
synchronized (mLock) {
- outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowId(targetWindowId);
+ outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowIdLocked(targetWindowId);
for (int i = 0; i < outsideWindowsIds.size(); i++) {
connectionList.add(getConnectionLocked(outsideWindowsIds.get(i)));
}
@@ -3684,13 +3684,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return mWindowInfoById.get(windowId);
}
- private List<Integer> getWatchOutsideTouchWindowId(int targetWindowId) {
- if (mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
+ private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) {
+ final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
+ if (targetWindow != null && mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
final List<Integer> outsideWindowsId = new ArrayList<>();
- final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
for (int i = 0; i < mWindowInfoById.size(); i++) {
WindowInfo window = mWindowInfoById.valueAt(i);
- if (window.layer < targetWindow.layer
+ if (window != null && window.layer < targetWindow.layer
&& window.hasFlagWatchOutsideTouch) {
outsideWindowsId.add(mWindowInfoById.keyAt(i));
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index da52d408e125..39866a72ab98 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -56,6 +56,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -629,10 +630,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
providerUserId, true);
} else {
- final String dialogMessage = mPackageManagerInternal.getSuspendedDialogMessage(
- providerPackage, providerUserId);
+ final SuspendDialogInfo dialogInfo = mPackageManagerInternal
+ .getSuspendedDialogInfo(providerPackage, providerUserId);
onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
- providerPackage, suspendingPackage, dialogMessage, providerUserId);
+ providerPackage, suspendingPackage, dialogInfo, providerUserId);
}
} else if (provider.maskedByQuietProfile) {
showBadge = true;
diff --git a/services/art-profile b/services/art-profile
index 328f8f7a37a7..4168a3f4b28c 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -207,7 +207,7 @@ HPLandroid/hardware/weaver/V1_0/IWeaver;->read(ILjava/util/ArrayList;Landroid/ha
HPLandroid/hardware/weaver/V1_0/IWeaver;->setHALInstrumentation()V
HPLandroid/hardware/weaver/V1_0/IWeaver;->unlinkToDeath(Landroid/os/IHwBinder$DeathRecipient;)Z
HPLandroid/hardware/weaver/V1_0/IWeaver;->write(ILjava/util/ArrayList;Ljava/util/ArrayList;)I
-HPLandroid/media/IMediaExtractorUpdateService;->loadPlugins(Ljava/lang/String;)V
+HPLandroid/media/IMediaUpdateService;->loadPlugins(Ljava/lang/String;)V
HPLandroid/net/apf/ApfGenerator$Instruction;-><init>(Landroid/net/apf/ApfGenerator;Landroid/net/apf/ApfGenerator$Opcodes;Landroid/net/apf/ApfGenerator$Register;)V
HPLandroid/net/apf/ApfGenerator$Instruction;->calculateImmSize(IZ)B
HPLandroid/net/apf/ApfGenerator$Instruction;->calculateTargetLabelOffset()I
@@ -3977,9 +3977,9 @@ PLandroid/hardware/weaver/V1_0/WeaverConfig;->readFromParcel(Landroid/os/HwParce
PLandroid/hardware/weaver/V1_0/WeaverReadResponse;-><init>()V
PLandroid/hardware/weaver/V1_0/WeaverReadResponse;->readEmbeddedFromParcel(Landroid/os/HwParcel;Landroid/os/HwBlob;J)V
PLandroid/hardware/weaver/V1_0/WeaverReadResponse;->readFromParcel(Landroid/os/HwParcel;)V
-PLandroid/media/IMediaExtractorUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-PLandroid/media/IMediaExtractorUpdateService$Stub$Proxy;->loadPlugins(Ljava/lang/String;)V
-PLandroid/media/IMediaExtractorUpdateService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaExtractorUpdateService;
+PLandroid/media/IMediaUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+PLandroid/media/IMediaUpdateService$Stub$Proxy;->loadPlugins(Ljava/lang/String;)V
+PLandroid/media/IMediaUpdateService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaExtractorUpdateService;
PLandroid/net/apf/-$$Lambda$ApfFilter$UV1wDVoVlbcxpr8zevj_aMFtUGw;-><init>()V
PLandroid/net/apf/-$$Lambda$ApfFilter$UV1wDVoVlbcxpr8zevj_aMFtUGw;->applyAsInt(Ljava/lang/Object;)I
PLandroid/net/apf/ApfCapabilities;-><init>(III)V
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1b97926d39fb..eb31e782eb33 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -159,7 +159,7 @@ import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
-public class BackupManagerService implements BackupManagerServiceInterface {
+public class BackupManagerService {
public static final String TAG = "BackupManagerService";
public static final boolean DEBUG = true;
@@ -701,7 +701,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Utility: build a new random integer token. The low bits are the ordinal of the
// operation for near-time uniqueness, and the upper bits are random for app-
// side unpredictability.
- @Override
public int generateRandomIntegerToken() {
int token = mTokenGenerator.nextInt();
if (token < 0) token = -token;
@@ -1108,12 +1107,10 @@ public class BackupManagerService implements BackupManagerServiceInterface {
return array;
}
- @Override
public boolean setBackupPassword(String currentPw, String newPw) {
return mBackupPasswordManager.setBackupPassword(currentPw, newPw);
}
- @Override
public boolean hasBackupPassword() {
return mBackupPasswordManager.hasBackupPassword();
}
@@ -1590,7 +1587,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Get the restore-set token for the best-available restore set for this package:
// the active set if possible, else the ancestral one. Returns zero if none available.
- @Override
public long getAvailableRestoreToken(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getAvailableRestoreToken");
@@ -1608,12 +1604,10 @@ public class BackupManagerService implements BackupManagerServiceInterface {
return token;
}
- @Override
public int requestBackup(String[] packages, IBackupObserver observer, int flags) {
return requestBackup(packages, observer, null, flags);
}
- @Override
public int requestBackup(String[] packages, IBackupObserver observer,
IBackupManagerMonitor monitor, int flags) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
@@ -1702,7 +1696,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Cancel all running backups.
- @Override
public void cancelBackups() {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups");
if (MORE_DEBUG) {
@@ -1732,7 +1725,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback,
int operationType) {
if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) {
@@ -1790,7 +1782,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// synchronous waiter case
- @Override
public boolean waitUntilOperationComplete(int token) {
if (MORE_DEBUG) {
Slog.i(TAG, "Blocking until operation complete for "
@@ -1895,7 +1886,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
- @Override
public void tearDownAgentAndKill(ApplicationInfo app) {
if (app == null) {
// Null means the system package, so just quietly move on. :)
@@ -2049,7 +2039,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
* @return Whether ongoing work will continue. The return value here will be passed
* along as the return value to the scheduled job's onStartJob() callback.
*/
- @Override
public boolean beginFullBackup(FullBackupJob scheduledJob) {
final long now = System.currentTimeMillis();
final long fullBackupInterval;
@@ -2224,7 +2213,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// The job scheduler says our constraints don't hold any more,
// so tear down any ongoing backup task right away.
- @Override
public void endFullBackup() {
// offload the mRunningFullBackupTask.handleCancel() call to another thread,
// as we might have to wait for mCancelLock
@@ -2331,7 +2319,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// ----- IBackupManager binder interface -----
- @Override
public void dataChanged(final String packageName) {
final int callingUserHandle = UserHandle.getCallingUserId();
if (callingUserHandle != UserHandle.USER_SYSTEM) {
@@ -2362,7 +2349,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Run an initialize operation for the given transport
- @Override
public void initializeTransports(String[] transportNames, IBackupObserver observer) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
"initializeTransport");
@@ -2382,7 +2368,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Clear the given package's backup data from the current transport
- @Override
public void clearBackupData(String transportName, String packageName) {
if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
PackageInfo info;
@@ -2438,7 +2423,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Run a backup pass immediately for any applications that have declared
// that they have pending updates.
- @Override
public void backupNow() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
@@ -2480,7 +2464,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
//
// This is the variant used by 'adb backup'; it requires on-screen confirmation
// by the user because it can be used to offload data over untrusted USB.
- @Override
public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
boolean compress, boolean doKeyValue, String[] pkgList) {
@@ -2558,7 +2541,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public void fullTransportBackup(String[] pkgNames) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
"fullTransportBackup");
@@ -2618,7 +2600,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public void adbRestore(ParcelFileDescriptor fd) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore");
@@ -2719,7 +2700,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Confirm that the previously-requested full backup/restore operation can proceed. This
// is used to require a user-facing disclosure about the operation.
- @Override
public void acknowledgeAdbBackupOrRestore(int token, boolean allow,
String curPassword, String encPpassword, IFullBackupRestoreObserver observer) {
if (DEBUG) {
@@ -2819,7 +2799,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Enable/disable backups
- @Override
public void setBackupEnabled(boolean enable) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"setBackupEnabled");
@@ -2887,7 +2866,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Enable/disable automatic restore of app data at install time
- @Override
public void setAutoRestore(boolean doAutoRestore) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"setAutoRestore");
@@ -2907,7 +2885,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Mark the backup service as having been provisioned
- @Override
public void setBackupProvisioned(boolean available) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"setBackupProvisioned");
@@ -2917,7 +2894,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Report whether the backup mechanism is currently enabled
- @Override
public boolean isBackupEnabled() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"isBackupEnabled");
@@ -2925,7 +2901,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Report the name of the currently active transport
- @Override
public String getCurrentTransport() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getCurrentTransport");
@@ -2938,7 +2913,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
* Returns the {@link ComponentName} of the host service of the selected transport or {@code
* null} if no transport selected or if the transport selected is not registered.
*/
- @Override
@Nullable
public ComponentName getCurrentTransportComponent() {
mContext.enforceCallingOrSelfPermission(
@@ -2954,7 +2928,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Report all known, available backup transports
- @Override
public String[] listAllTransports() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"listAllTransports");
@@ -2962,14 +2935,12 @@ public class BackupManagerService implements BackupManagerServiceInterface {
return mTransportManager.getRegisteredTransportNames();
}
- @Override
public ComponentName[] listAllTransportComponents() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"listAllTransportComponents");
return mTransportManager.getRegisteredTransportComponents();
}
- @Override
public String[] getTransportWhitelist() {
// No permission check, intentionally.
Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist();
@@ -3006,7 +2977,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
*/
- @Override
public void updateTransportAttributes(
ComponentName transportComponent,
String name,
@@ -3070,7 +3040,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
/** Selects transport {@code transportName} and returns previous selected transport. */
- @Override
@Deprecated
@Nullable
public String selectBackupTransport(String transportName) {
@@ -3089,7 +3058,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public void selectBackupTransportAsync(
ComponentName transportComponent, ISelectBackupTransportCallback listener) {
mContext.enforceCallingOrSelfPermission(
@@ -3161,7 +3129,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Supply the configuration Intent for the given transport. If the name is not one
// of the available transports, or if the transport does not supply any configuration
// UI, the method returns null.
- @Override
public Intent getConfigurationIntent(String transportName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getConfigurationIntent");
@@ -3186,7 +3153,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
* @param transportName The name of the registered transport.
* @return The current destination string or null if the transport is not registered.
*/
- @Override
public String getDestinationString(String transportName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "getDestinationString");
@@ -3204,7 +3170,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Supply the manage-data intent for the given transport.
- @Override
public Intent getDataManagementIntent(String transportName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementIntent");
@@ -3223,7 +3188,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Supply the menu label for affordances that fire the manage-data intent
// for the given transport.
- @Override
public String getDataManagementLabel(String transportName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementLabel");
@@ -3242,7 +3206,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Callback: a requested backup agent has been instantiated. This should only
// be called from the Activity Manager.
- @Override
public void agentConnected(String packageName, IBinder agentBinder) {
synchronized (mAgentConnectLock) {
if (Binder.getCallingUid() == Process.SYSTEM_UID) {
@@ -3261,7 +3224,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Callback: a backup agent has failed to come up, or has unexpectedly quit.
// If the agent failed to come up in the first place, the agentBinder argument
// will be null. This should only be called from the Activity Manager.
- @Override
public void agentDisconnected(String packageName) {
// TODO: handle backup being interrupted
synchronized (mAgentConnectLock) {
@@ -3278,7 +3240,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// An application being installed will need a restore pass, then the Package Manager
// will need to be told when the restore is finished.
- @Override
public void restoreAtInstall(String packageName, int token) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
@@ -3364,7 +3325,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
// Hand off a restore session
- @Override
public IRestoreSession beginRestoreSession(String packageName, String transport) {
if (DEBUG) {
Slog.v(TAG, "beginRestoreSession: pkg=" + packageName
@@ -3430,7 +3390,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Note that a currently-active backup agent has notified us that it has
// completed the given outstanding asynchronous backup/restore operation.
- @Override
public void opComplete(int token, long result) {
if (MORE_DEBUG) {
Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result);
@@ -3468,7 +3427,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public boolean isAppEligibleForBackup(String packageName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "isAppEligibleForBackup");
@@ -3490,7 +3448,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public String[] filterAppsEligibleForBackup(String[] packages) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "filterAppsEligibleForBackup");
@@ -3517,7 +3474,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
}
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -3667,7 +3623,6 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
- @Override
public IBackupManager getBackupManagerBinder() {
return mBackupManagerBinder;
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
deleted file mode 100644
index a38a0e9918d2..000000000000
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ /dev/null
@@ -1,199 +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.server.backup;
-
-import android.annotation.Nullable;
-import android.app.IBackupAgent;
-import android.app.backup.IBackupManager;
-import android.app.backup.IBackupManagerMonitor;
-import android.app.backup.IBackupObserver;
-import android.app.backup.IFullBackupRestoreObserver;
-import android.app.backup.IRestoreSession;
-import android.app.backup.ISelectBackupTransportCallback;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Interface for BackupManagerService.
- *
- * Current and future implementations of BackupManagerService should use this interface, so that
- * Trampoline is able to switch between them.
- */
-public interface BackupManagerServiceInterface {
-
- void unlockSystemUser();
-
- // Utility: build a new random integer token
- int generateRandomIntegerToken();
-
- boolean setBackupPassword(String currentPw, String newPw);
-
- boolean hasBackupPassword();
-
- // Get the restore-set token for the best-available restore set for this package:
- // the active set if possible, else the ancestral one. Returns zero if none available.
- long getAvailableRestoreToken(String packageName);
-
- int requestBackup(String[] packages, IBackupObserver observer, int flags);
-
- int requestBackup(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags);
-
- // Cancel all running backups.
- void cancelBackups();
-
- void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback,
- int operationType);
-
- // synchronous waiter case
- boolean waitUntilOperationComplete(int token);
-
- void tearDownAgentAndKill(ApplicationInfo app);
-
- boolean beginFullBackup(FullBackupJob scheduledJob);
-
- // The job scheduler says our constraints don't hold any more,
- // so tear down any ongoing backup task right away.
- void endFullBackup();
-
- void dataChanged(String packageName);
-
- // Initialize the given transport
- void initializeTransports(String[] transportName, IBackupObserver observer);
-
- // Clear the given package's backup data from the current transport
- void clearBackupData(String transportName, String packageName);
-
- // Run a backup pass immediately for any applications that have declared
- // that they have pending updates.
- void backupNow();
-
- // Run a backup pass for the given packages, writing the resulting data stream
- // to the supplied file descriptor. This method is synchronous and does not return
- // to the caller until the backup has been completed.
- //
- // This is the variant used by 'adb backup'; it requires on-screen confirmation
- // by the user because it can be used to offload data over untrusted USB.
- void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
- boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
- boolean compress, boolean doKeyValue, String[] pkgList);
-
- void fullTransportBackup(String[] pkgNames);
-
- void adbRestore(ParcelFileDescriptor fd);
-
- // Confirm that the previously-requested full backup/restore operation can proceed. This
- // is used to require a user-facing disclosure about the operation.
- void acknowledgeAdbBackupOrRestore(int token, boolean allow,
- String curPassword, String encPpassword, IFullBackupRestoreObserver observer);
-
- // Enable/disable backups
- void setBackupEnabled(boolean enable);
-
- // Enable/disable automatic restore of app data at install time
- void setAutoRestore(boolean doAutoRestore);
-
- // Mark the backup service as having been provisioned
- void setBackupProvisioned(boolean available);
-
- // Report whether the backup mechanism is currently enabled
- boolean isBackupEnabled();
-
- // Update the transport attributes
- void updateTransportAttributes(
- ComponentName transportComponent,
- String name,
- Intent configurationIntent,
- String currentDestinationString,
- Intent dataManagementIntent,
- String dataManagementLabel);
-
- // Report the name of the currently active transport
- String getCurrentTransport();
-
- // Report the component name of the host service of the currently active transport
- @Nullable
- ComponentName getCurrentTransportComponent();
-
- // Report all known, available backup transports
- String[] listAllTransports();
-
- ComponentName[] listAllTransportComponents();
-
- String[] getTransportWhitelist();
-
- // Select which transport to use for the next backup operation.
- String selectBackupTransport(String transport);
-
- void selectBackupTransportAsync(ComponentName transport,
- ISelectBackupTransportCallback listener);
-
- // Supply the configuration Intent for the given transport. If the name is not one
- // of the available transports, or if the transport does not supply any configuration
- // UI, the method returns null.
- Intent getConfigurationIntent(String transportName);
-
- // Supply the configuration summary string for the given transport. If the name is
- // not one of the available transports, or if the transport does not supply any
- // summary / destination string, the method can return null.
- //
- // This string is used VERBATIM as the summary text of the relevant Settings item!
- String getDestinationString(String transportName);
-
- // Supply the manage-data intent for the given transport.
- Intent getDataManagementIntent(String transportName);
-
- // Supply the menu label for affordances that fire the manage-data intent
- // for the given transport.
- String getDataManagementLabel(String transportName);
-
- // Callback: a requested backup agent has been instantiated. This should only
- // be called from the Activity Manager.
- void agentConnected(String packageName, IBinder agentBinder);
-
- // Callback: a backup agent has failed to come up, or has unexpectedly quit.
- // If the agent failed to come up in the first place, the agentBinder argument
- // will be null. This should only be called from the Activity Manager.
- void agentDisconnected(String packageName);
-
- // An application being installed will need a restore pass, then the Package Manager
- // will need to be told when the restore is finished.
- void restoreAtInstall(String packageName, int token);
-
- // Hand off a restore session
- IRestoreSession beginRestoreSession(String packageName, String transport);
-
- // Note that a currently-active backup agent has notified us that it has
- // completed the given outstanding asynchronous backup/restore operation.
- void opComplete(int token, long result);
-
- boolean isAppEligibleForBackup(String packageName);
-
- String[] filterAppsEligibleForBackup(String[] packages);
-
- void dump(FileDescriptor fd, PrintWriter pw, String[] args);
-
- IBackupManager getBackupManagerBinder();
-
- // Gets access to the backup/restore agent timeout parameters.
- BackupAgentTimeoutParameters getAgentTimeoutParameters();
-}
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
index fbec5cb22af2..bb145769fc8c 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
@@ -39,7 +39,7 @@ public class KeyValueAdbRestoreEngine implements Runnable {
private static final String TAG = "KeyValueAdbRestoreEngine";
private static final boolean DEBUG = false;
- private final BackupManagerServiceInterface mBackupManagerService;
+ private final BackupManagerService mBackupManagerService;
private final File mDataDir;
FileMetadata mInfo;
@@ -48,7 +48,7 @@ public class KeyValueAdbRestoreEngine implements Runnable {
IBackupAgent mAgent;
int mToken;
- public KeyValueAdbRestoreEngine(BackupManagerServiceInterface backupManagerService,
+ public KeyValueAdbRestoreEngine(BackupManagerService backupManagerService,
File dataDir, FileMetadata info, ParcelFileDescriptor inFD, IBackupAgent agent,
int token) {
mBackupManagerService = backupManagerService;
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 787d667afe51..818154b283da 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -76,7 +76,7 @@ public class Trampoline extends IBackupManager.Stub {
final Context mContext;
final File mSuppressFile; // existence testing & creating synchronized on 'this'
final boolean mGlobalDisable;
- volatile BackupManagerServiceInterface mService;
+ volatile BackupManagerService mService;
private HandlerThread mHandlerThread;
@@ -100,7 +100,7 @@ public class Trampoline extends IBackupManager.Stub {
BACKUP_SUPPRESS_FILENAME);
}
- protected BackupManagerServiceInterface createBackupManagerService() {
+ protected BackupManagerService createBackupManagerService() {
return BackupManagerService.create(mContext, this, mHandlerThread);
}
@@ -135,7 +135,7 @@ public class Trampoline extends IBackupManager.Stub {
initialize(UserHandle.USER_SYSTEM);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
Slog.i(TAG, "Unlocking system user; mService=" + mService);
if (svc != null) {
svc.unlockSystemUser();
@@ -198,7 +198,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void dataChanged(String packageName) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.dataChanged(packageName);
}
@@ -207,7 +207,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void initializeTransports(String[] transportNames, IBackupObserver observer)
throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.initializeTransports(transportNames, observer);
}
@@ -216,7 +216,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void clearBackupData(String transportName, String packageName)
throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.clearBackupData(transportName, packageName);
}
@@ -224,7 +224,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void agentConnected(String packageName, IBinder agent) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.agentConnected(packageName, agent);
}
@@ -232,7 +232,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void agentDisconnected(String packageName) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.agentDisconnected(packageName);
}
@@ -240,7 +240,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void restoreAtInstall(String packageName, int token) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.restoreAtInstall(packageName, token);
}
@@ -248,7 +248,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void setBackupEnabled(boolean isEnabled) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.setBackupEnabled(isEnabled);
}
@@ -256,7 +256,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.setAutoRestore(doAutoRestore);
}
@@ -264,7 +264,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void setBackupProvisioned(boolean isProvisioned) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.setBackupProvisioned(isProvisioned);
}
@@ -272,25 +272,25 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public boolean isBackupEnabled() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.isBackupEnabled() : false;
}
@Override
public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false;
}
@Override
public boolean hasBackupPassword() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.hasBackupPassword() : false;
}
@Override
public void backupNow() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.backupNow();
}
@@ -301,7 +301,7 @@ public class Trampoline extends IBackupManager.Stub {
boolean includeShared, boolean doWidgets, boolean allApps,
boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames)
throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets,
allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
@@ -310,7 +310,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void fullTransportBackup(String[] packageNames) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.fullTransportBackup(packageNames);
}
@@ -318,7 +318,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void adbRestore(ParcelFileDescriptor fd) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.adbRestore(fd);
}
@@ -328,7 +328,7 @@ public class Trampoline extends IBackupManager.Stub {
public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
String encryptionPassword, IFullBackupRestoreObserver observer)
throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.acknowledgeAdbBackupOrRestore(token, allow,
curPassword, encryptionPassword, observer);
@@ -337,7 +337,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public String getCurrentTransport() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getCurrentTransport() : null;
}
@@ -348,25 +348,25 @@ public class Trampoline extends IBackupManager.Stub {
@Override
@Nullable
public ComponentName getCurrentTransportComponent() {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getCurrentTransportComponent() : null;
}
@Override
public String[] listAllTransports() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.listAllTransports() : null;
}
@Override
public ComponentName[] listAllTransportComponents() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.listAllTransportComponents() : null;
}
@Override
public String[] getTransportWhitelist() {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getTransportWhitelist() : null;
}
@@ -378,7 +378,7 @@ public class Trampoline extends IBackupManager.Stub {
String currentDestinationString,
@Nullable Intent dataManagementIntent,
String dataManagementLabel) {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.updateTransportAttributes(
transportComponent,
@@ -392,14 +392,14 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public String selectBackupTransport(String transport) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.selectBackupTransport(transport) : null;
}
@Override
public void selectBackupTransportAsync(ComponentName transport,
ISelectBackupTransportCallback listener) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.selectBackupTransportAsync(transport, listener);
} else {
@@ -415,38 +415,38 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public Intent getConfigurationIntent(String transport) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getConfigurationIntent(transport) : null;
}
@Override
public String getDestinationString(String transport) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getDestinationString(transport) : null;
}
@Override
public Intent getDataManagementIntent(String transport) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getDataManagementIntent(transport) : null;
}
@Override
public String getDataManagementLabel(String transport) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getDataManagementLabel(transport) : null;
}
@Override
public IRestoreSession beginRestoreSession(String packageName, String transportID)
throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null;
}
@Override
public void opComplete(int token, long result) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.opComplete(token, result);
}
@@ -454,26 +454,26 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public long getAvailableRestoreToken(String packageName) {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0;
}
@Override
public boolean isAppEligibleForBackup(String packageName) {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
}
@Override
public String[] filterAppsEligibleForBackup(String[] packages) {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.filterAppsEligibleForBackup(packages) : null;
}
@Override
public int requestBackup(String[] packages, IBackupObserver observer,
IBackupManagerMonitor monitor, int flags) throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc == null) {
return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
}
@@ -482,7 +482,7 @@ public class Trampoline extends IBackupManager.Stub {
@Override
public void cancelBackups() throws RemoteException {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.cancelBackups();
}
@@ -492,7 +492,7 @@ public class Trampoline extends IBackupManager.Stub {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.dump(fd, pw, args);
} else {
@@ -503,12 +503,12 @@ public class Trampoline extends IBackupManager.Stub {
// Full backup/restore entry points - non-Binder; called directly
// by the full-backup scheduled job
/* package */ boolean beginFullBackup(FullBackupJob scheduledJob) {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
return (svc != null) ? svc.beginFullBackup(scheduledJob) : false;
}
/* package */ void endFullBackup() {
- BackupManagerServiceInterface svc = mService;
+ BackupManagerService svc = mService;
if (svc != null) {
svc.endFullBackup();
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 6904b3fc6b9c..3a5232a6b97a 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -708,8 +708,6 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
} else {
throw TaskException.create();
}
- } finally {
- mBlankStateFile.delete();
}
checkAgentResult(packageInfo, agentResult);
}
@@ -1037,8 +1035,13 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
private void cleanUpAgent(@StateTransaction int stateTransaction) {
applyStateTransaction(stateTransaction);
- mBackupDataFile.delete();
+ if (mBackupDataFile != null) {
+ mBackupDataFile.delete();
+ }
mBlankStateFile.delete();
+ mSavedStateFile = null;
+ mBackupDataFile = null;
+ mNewStateFile = null;
tryCloseFileDescriptor(mSavedState, "old state");
tryCloseFileDescriptor(mBackupData, "backup data");
tryCloseFileDescriptor(mNewState, "new state");
@@ -1059,7 +1062,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
mNewStateFile.renameTo(mSavedStateFile);
break;
case StateTransaction.DISCARD_NEW:
- mNewStateFile.delete();
+ if (mNewStateFile != null) {
+ mNewStateFile.delete();
+ }
break;
case StateTransaction.DISCARD_ALL:
mSavedStateFile.delete();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9519e015f67..2fa2941efe7f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -4,6 +4,7 @@ java_library_static {
aidl: {
include_dirs: [
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"system/core/storaged/binder",
"system/netd/server/binder",
"system/vold/binder",
@@ -11,6 +12,7 @@ java_library_static {
},
srcs: [
"java/**/*.java",
+ ":dumpstate_aidl",
":netd_aidl",
":netd_metrics_aidl",
":installd_aidl",
@@ -44,6 +46,7 @@ java_library_static {
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.0-java",
+ "netd_aidl_interface-java",
],
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5e8ffb79c493..b750d7959167 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1679,6 +1679,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
"ConnectivityService");
}
+ private void enforceAnyPermissionOf(String... permissions) {
+ for (String permission : permissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return;
+ }
+ }
+ throw new SecurityException(
+ "Requires one of the following permissions: " + String.join(", ", permissions) + ".");
+ }
+
private void enforceInternetPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERNET,
@@ -1723,6 +1733,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
"ConnectivityService");
}
+ private void enforceNetworkStackSettingsOrSetup() {
+ enforceAnyPermissionOf(
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK);
+ }
+
private boolean checkNetworkStackPermission() {
return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
android.Manifest.permission.NETWORK_STACK);
@@ -1798,7 +1815,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void sendStickyBroadcast(Intent intent) {
synchronized (this) {
- if (!mSystemReady) {
+ if (!mSystemReady
+ && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mInitialBroadcast = new Intent(intent);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1847,8 +1865,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mInitialBroadcast = null;
}
}
- // load the global proxy at startup
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
// Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
// for user to unlock device too.
@@ -3089,7 +3105,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
- handleDeprecatedGlobalHttpProxy();
+ mProxyTracker.loadDeprecatedGlobalHttpProxy();
break;
}
case EVENT_PROXY_HAS_CHANGED: {
@@ -3479,30 +3495,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.getDefaultProxy());
- }
- }
-
- private void handleDeprecatedGlobalHttpProxy() {
- final String proxy = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.HTTP_PROXY);
- if (!TextUtils.isEmpty(proxy)) {
- String data[] = proxy.split(":");
- if (data.length == 0) {
- return;
- }
-
- final String proxyHost = data[0];
- int proxyPort = 8080;
- if (data.length > 1) {
- try {
- proxyPort = Integer.parseInt(data[1]);
- } catch (NumberFormatException e) {
- return;
- }
- }
- final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
- setGlobalProxy(p);
+ mProxyTracker.sendProxyBroadcast();
}
}
@@ -4008,7 +4001,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void setAirplaneMode(boolean enable) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackSettingsOrSetup();
final long ident = Binder.clearCallingIdentity();
try {
final ContentResolver cr = mContext.getContentResolver();
@@ -4789,15 +4782,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private String getNetworkPermission(NetworkCapabilities nc) {
- // TODO: make these permission strings AIDL constants instead.
+ private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
- return NetworkManagementService.PERMISSION_SYSTEM;
+ return INetd.PERMISSION_SYSTEM;
}
if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
- return NetworkManagementService.PERMISSION_NETWORK;
+ return INetd.PERMISSION_NETWORK;
}
- return null;
+ return INetd.PERMISSION_NONE;
}
/**
@@ -4870,9 +4862,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (Objects.equals(nai.networkCapabilities, newNc)) return;
- final String oldPermission = getNetworkPermission(nai.networkCapabilities);
- final String newPermission = getNetworkPermission(newNc);
- if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
+ final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+ final int newPermission = getNetworkPermission(newNc);
+ if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
try {
mNMS.setNetworkPermission(nai.network.netId, newPermission);
} catch (RemoteException e) {
@@ -5537,15 +5529,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (networkAgent.isVPN()) {
// Temporarily disable the default proxy (not global).
- synchronized (mProxyTracker.mProxyLock) {
- if (!mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = true;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(null);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(false);
// TODO: support proxy per network.
}
@@ -5567,15 +5551,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- synchronized (mProxyTracker.mProxyLock) {
- if (mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = false;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(true);
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
disconnectAndDestroyNetwork(networkAgent);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 26421a2acb66..0b30ff5cc398 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -242,11 +242,9 @@ public class DeviceIdleController extends SystemService
private ActivityTaskManagerInternal mLocalActivityTaskManager;
private PowerManagerInternal mLocalPowerManager;
private PowerManager mPowerManager;
- private ConnectivityService mConnectivityService;
private INetworkPolicyManager mNetworkPolicyManager;
private SensorManager mSensorManager;
private Sensor mMotionSensor;
- private LocationManager mLocationManager;
private LocationRequest mLocationRequest;
private Intent mIdleIntent;
private Intent mLightIdleIntent;
@@ -1508,6 +1506,8 @@ public class DeviceIdleController extends SystemService
static class Injector {
private final Context mContext;
+ private ConnectivityService mConnectivityService;
+ private LocationManager mLocationManager;
Injector(Context ctx) {
mContext = ctx;
@@ -1527,7 +1527,11 @@ public class DeviceIdleController extends SystemService
}
ConnectivityService getConnectivityService() {
- return (ConnectivityService) ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ if (mConnectivityService == null) {
+ mConnectivityService = (ConnectivityService) ServiceManager.getService(
+ Context.CONNECTIVITY_SERVICE);
+ }
+ return mConnectivityService;
}
Constants getConstants(DeviceIdleController controller, Handler handler,
@@ -1536,7 +1540,10 @@ public class DeviceIdleController extends SystemService
}
LocationManager getLocationManager() {
- return mContext.getSystemService(LocationManager.class);
+ if (mLocationManager == null) {
+ mLocationManager = mContext.getSystemService(LocationManager.class);
+ }
+ return mLocationManager;
}
MyHandler getHandler(DeviceIdleController controller) {
@@ -1666,7 +1673,6 @@ public class DeviceIdleController extends SystemService
mGoingIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"deviceidle_going_idle");
mGoingIdleWakeLock.setReferenceCounted(true);
- mConnectivityService = mInjector.getConnectivityService();
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class);
@@ -1689,7 +1695,6 @@ public class DeviceIdleController extends SystemService
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
- mLocationManager = mInjector.getLocationManager();
mLocationRequest = new LocationRequest()
.setQuality(LocationRequest.ACCURACY_FINE)
.setInterval(0)
@@ -2160,10 +2165,17 @@ public class DeviceIdleController extends SystemService
}
}
+ @VisibleForTesting
+ boolean isNetworkConnected() {
+ synchronized (this) {
+ return mNetworkConnected;
+ }
+ }
+
void updateConnectivityState(Intent connIntent) {
ConnectivityService cm;
synchronized (this) {
- cm = mConnectivityService;
+ cm = mInjector.getConnectivityService();
}
if (cm == null) {
return;
@@ -2276,13 +2288,17 @@ public class DeviceIdleController extends SystemService
/** Must only be used in tests. */
@VisibleForTesting
void setDeepEnabledForTest(boolean enabled) {
- mDeepEnabled = enabled;
+ synchronized (this) {
+ mDeepEnabled = enabled;
+ }
}
/** Must only be used in tests. */
@VisibleForTesting
void setLightEnabledForTest(boolean enabled) {
- mLightEnabled = enabled;
+ synchronized (this) {
+ mLightEnabled = enabled;
+ }
}
void becomeInactiveIfAppropriateLocked() {
@@ -2338,7 +2354,9 @@ public class DeviceIdleController extends SystemService
*/
@VisibleForTesting
void setLightStateForTest(int lightState) {
- mLightState = lightState;
+ synchronized (this) {
+ mLightState = lightState;
+ }
}
@VisibleForTesting
@@ -2429,12 +2447,6 @@ public class DeviceIdleController extends SystemService
}
}
- /** Must only be used in tests. */
- @VisibleForTesting
- void setLocationManagerForTest(LocationManager lm) {
- mLocationManager = lm;
- }
-
@VisibleForTesting
int getState() {
return mState;
@@ -2486,18 +2498,19 @@ public class DeviceIdleController extends SystemService
if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING.");
EventLogTags.writeDeviceIdle(mState, reason);
scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);
- if (mLocationManager != null
- && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
- mLocationManager.requestLocationUpdates(mLocationRequest,
+ LocationManager locationManager = mInjector.getLocationManager();
+ if (locationManager != null
+ && locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+ locationManager.requestLocationUpdates(mLocationRequest,
mGenericLocationListener, mHandler.getLooper());
mLocating = true;
} else {
mHasNetworkLocation = false;
}
- if (mLocationManager != null
- && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+ if (locationManager != null
+ && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
mHasGps = true;
- mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
mGpsLocationListener, mHandler.getLooper());
mLocating = true;
} else {
@@ -2575,7 +2588,9 @@ public class DeviceIdleController extends SystemService
/** Must only be used in tests. */
@VisibleForTesting
void setActiveIdleOpsForTest(int count) {
- mActiveIdleOpCount = count;
+ synchronized (this) {
+ mActiveIdleOpCount = count;
+ }
}
void setJobsActive(boolean active) {
@@ -2751,8 +2766,9 @@ public class DeviceIdleController extends SystemService
void cancelLocatingLocked() {
if (mLocating) {
- mLocationManager.removeUpdates(mGenericLocationListener);
- mLocationManager.removeUpdates(mGpsLocationListener);
+ LocationManager locationManager = mInjector.getLocationManager();
+ locationManager.removeUpdates(mGenericLocationListener);
+ locationManager.removeUpdates(mGpsLocationListener);
mLocating = false;
}
}
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 96ce6a4ee6a4..6677541b1b32 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -109,14 +109,28 @@ public class LooperStatsService extends Binder {
"max_latency_micros",
"total_cpu_micros",
"max_cpu_micros",
+ "recorded_delay_message_count",
+ "total_delay_millis",
+ "max_delay_millis",
"exception_count"));
pw.println(header);
for (LooperStats.ExportedEntry entry : entries) {
- pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
- entry.threadName, entry.handlerClassName, entry.messageName,
- entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
- entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
- entry.maxCpuUsageMicros, entry.exceptionCount);
+ pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
+ entry.workSourceUid,
+ entry.threadName,
+ entry.handlerClassName,
+ entry.messageName,
+ entry.isInteractive,
+ entry.messageCount,
+ entry.recordedMessageCount,
+ entry.totalLatencyMicros,
+ entry.maxLatencyMicros,
+ entry.cpuUsageMicros,
+ entry.maxCpuUsageMicros,
+ entry.recordedDelayMessageCount,
+ entry.delayMillis,
+ entry.maxDelayMillis,
+ entry.exceptionCount);
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index de930f794e50..f510d8355179 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -57,6 +57,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
+import android.net.TetherStatsParcel;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
@@ -169,19 +170,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
*/
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
- /**
- * String to pass to netd to indicate that a network is only accessible
- * to apps that have the CHANGE_NETWORK_STATE permission.
- */
- public static final String PERMISSION_NETWORK = "NETWORK";
-
- /**
- * String to pass to netd to indicate that a network is only
- * accessible to system apps and those with the CONNECTIVITY_INTERNAL
- * permission.
- */
- public static final String PERMISSION_SYSTEM = "SYSTEM";
-
static class NetdResponseCode {
/* Keep in sync with system/netd/server/ResponseCode.h */
public static final int InterfaceListResult = 110;
@@ -222,6 +210,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
+ static final boolean MODIFY_OPERATION_ADD = true;
+ static final boolean MODIFY_OPERATION_REMOVE = false;
+
/**
* Binder context for this service
*/
@@ -1121,41 +1112,47 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void addRoute(int netId, RouteInfo route) {
- modifyRoute("add", "" + netId, route);
+ modifyRoute(MODIFY_OPERATION_ADD, netId, route);
}
@Override
public void removeRoute(int netId, RouteInfo route) {
- modifyRoute("remove", "" + netId, route);
+ modifyRoute(MODIFY_OPERATION_REMOVE, netId, route);
}
- private void modifyRoute(String action, String netId, RouteInfo route) {
+ private void modifyRoute(boolean add, int netId, RouteInfo route) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final Command cmd = new Command("network", "route", action, netId);
-
- // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
- cmd.appendArg(route.getInterface());
- cmd.appendArg(route.getDestination().toString());
+ final String ifName = route.getInterface();
+ final String dst = route.getDestination().toString();
+ final String nextHop;
switch (route.getType()) {
case RouteInfo.RTN_UNICAST:
if (route.hasGateway()) {
- cmd.appendArg(route.getGateway().getHostAddress());
+ nextHop = route.getGateway().getHostAddress();
+ } else {
+ nextHop = INetd.NEXTHOP_NONE;
}
break;
case RouteInfo.RTN_UNREACHABLE:
- cmd.appendArg("unreachable");
+ nextHop = INetd.NEXTHOP_UNREACHABLE;
break;
case RouteInfo.RTN_THROW:
- cmd.appendArg("throw");
+ nextHop = INetd.NEXTHOP_THROW;
+ break;
+ default:
+ nextHop = INetd.NEXTHOP_NONE;
break;
}
-
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ if (add) {
+ mNetdService.networkAddRoute(netId, ifName, dst, nextHop);
+ } else {
+ mNetdService.networkRemoveRoute(netId, ifName, dst, nextHop);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -1844,31 +1841,30 @@ public class NetworkManagementService extends INetworkManagementService.Stub
return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
- final PersistableBundle bundle;
+ final TetherStatsParcel[] tetherStatsVec;
try {
- bundle = mNetdService.tetherGetStats();
+ tetherStatsVec = mNetdService.tetherGetStats();
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException("problem parsing tethering stats: ", e);
}
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(),
- bundle.size());
+ tetherStatsVec.length);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String iface : bundle.keySet()) {
- long[] statsArray = bundle.getLongArray(iface);
+ for (TetherStatsParcel tetherStats : tetherStatsVec) {
try {
- entry.iface = iface;
+ entry.iface = tetherStats.iface;
entry.uid = UID_TETHERING;
entry.set = SET_DEFAULT;
entry.tag = TAG_NONE;
- entry.rxBytes = statsArray[INetd.TETHER_STATS_RX_BYTES];
- entry.rxPackets = statsArray[INetd.TETHER_STATS_RX_PACKETS];
- entry.txBytes = statsArray[INetd.TETHER_STATS_TX_BYTES];
- entry.txPackets = statsArray[INetd.TETHER_STATS_TX_PACKETS];
+ entry.rxBytes = tetherStats.rxBytes;
+ entry.rxPackets = tetherStats.rxPackets;
+ entry.txBytes = tetherStats.txBytes;
+ entry.txPackets = tetherStats.txPackets;
stats.combineValues(entry);
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalStateException("invalid tethering stats for " + iface, e);
+ throw new IllegalStateException("invalid tethering stats " + e);
}
}
@@ -1916,44 +1912,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "users";
- argv[1] = "add";
- argv[2] = netId;
- int argc = 3;
- // Avoid overly long commands by limiting number of UID ranges per command.
- for (int i = 0; i < ranges.length; i++) {
- argv[argc++] = ranges[i].toString();
- if (i == (ranges.length - 1) || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+
+ try {
+ mNetdService.networkAddUidRanges(netId, ranges);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
public void removeVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "users";
- argv[1] = "remove";
- argv[2] = netId;
- int argc = 3;
- // Avoid overly long commands by limiting number of UID ranges per command.
- for (int i = 0; i < ranges.length; i++) {
- argv[argc++] = ranges[i].toString();
- if (i == (ranges.length - 1) || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+ try {
+ mNetdService.networkRemoveUidRanges(netId, ranges);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2412,17 +2385,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
- public void createPhysicalNetwork(int netId, String permission) {
+ public void createPhysicalNetwork(int netId, int permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- if (permission != null) {
- mConnector.execute("network", "create", netId, permission);
- } else {
- mConnector.execute("network", "create", netId);
- }
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkCreatePhysical(netId, permission);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2431,10 +2400,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
- secure ? "1" : "0");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkCreateVpn(netId, hasDNS, secure);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2455,20 +2423,24 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void addInterfaceToNetwork(String iface, int netId) {
- modifyInterfaceInNetwork("add", "" + netId, iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
}
@Override
public void removeInterfaceFromNetwork(String iface, int netId) {
- modifyInterfaceInNetwork("remove", "" + netId, iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, netId, iface);
}
- private void modifyInterfaceInNetwork(String action, String netId, String iface) {
+ private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "interface", action, netId, iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ if (add) {
+ mNetdService.networkAddInterface(netId, iface);
+ } else {
+ mNetdService.networkRemoveInterface(netId, iface);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2476,20 +2448,20 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
-
- // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
final LinkAddress la = routeInfo.getDestinationLinkAddress();
- cmd.appendArg(routeInfo.getInterface());
- cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
+ final String ifName = routeInfo.getInterface();
+ final String dst = la.toString();
+ final String nextHop;
+
if (routeInfo.hasGateway()) {
- cmd.appendArg(routeInfo.getGateway().getHostAddress());
+ nextHop = routeInfo.getGateway().getHostAddress();
+ } else {
+ nextHop = "";
}
-
try {
- mConnector.execute(cmd);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkAddLegacyRoute(netId, ifName, dst, nextHop, uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2498,9 +2470,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "default", "set", netId);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetDefault(netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2509,49 +2481,41 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "default", "clear");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkClearDefault();
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
- public void setNetworkPermission(int netId, String permission) {
+ public void setNetworkPermission(int netId, int permission) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- if (permission != null) {
- mConnector.execute("network", "permission", "network", "set", permission, netId);
- } else {
- mConnector.execute("network", "permission", "network", "clear", netId);
- }
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetPermissionForNetwork(netId, permission);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
+ private int parsePermission(String permission) {
+ if (permission.equals("NETWORK")) {
+ return INetd.PERMISSION_NETWORK;
+ }
+ if (permission.equals("SYSTEM")) {
+ return INetd.PERMISSION_SYSTEM;
+ }
+ return INetd.PERMISSION_NONE;
+ }
@Override
public void setPermission(String permission, int[] uids) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "permission";
- argv[1] = "user";
- argv[2] = "set";
- argv[3] = permission;
- int argc = 4;
- // Avoid overly long commands by limiting number of UIDs per command.
- for (int i = 0; i < uids.length; ++i) {
- argv[argc++] = uids[i];
- if (i == uids.length - 1 || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 4;
- }
+ try {
+ mNetdService.networkSetPermissionForUser(parsePermission(permission), uids);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2559,22 +2523,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void clearPermission(int[] uids) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
- argv[0] = "permission";
- argv[1] = "user";
- argv[2] = "clear";
- int argc = 3;
- // Avoid overly long commands by limiting number of UIDs per command.
- for (int i = 0; i < uids.length; ++i) {
- argv[argc++] = uids[i];
- if (i == uids.length - 1 || argc == argv.length) {
- try {
- mConnector.execute("network", Arrays.copyOf(argv, argc));
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- argc = 3;
- }
+ try {
+ mNetdService.networkClearPermissionForUser(uids);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2583,9 +2535,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "protect", "allow", uid);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetProtectAllow(uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@@ -2594,26 +2546,26 @@ public class NetworkManagementService extends INetworkManagementService.Stub
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("network", "protect", "deny", uid);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
+ mNetdService.networkSetProtectDeny(uid);
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
}
}
@Override
public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
- modifyInterfaceInNetwork("add", "local", iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, iface);
for (RouteInfo route : routes) {
if (!route.isDefaultRoute()) {
- modifyRoute("add", "local", route);
+ modifyRoute(MODIFY_OPERATION_ADD, INetd.NETID_LOCAL, route);
}
}
}
@Override
public void removeInterfaceFromLocalNetwork(String iface) {
- modifyInterfaceInNetwork("remove", "local", iface);
+ modifyInterfaceInNetwork(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, iface);
}
@Override
@@ -2622,7 +2574,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
for (RouteInfo route : routes) {
try {
- modifyRoute("remove", "local", route);
+ modifyRoute(MODIFY_OPERATION_REMOVE, INetd.NETID_LOCAL, route);
} catch (IllegalStateException e) {
failures++;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 21f54dd33d3e..7c67596d92b4 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3754,7 +3754,7 @@ class StorageManagerService extends IStorageManager.Stub
}
@Override
- public void mountExternalStorageForApp(String packageName, int appId, String sharedUserId,
+ public void prepareSandboxForApp(String packageName, int appId, String sharedUserId,
int userId) {
final String sandboxId;
synchronized (mPackagesLock) {
@@ -3771,7 +3771,41 @@ class StorageManagerService extends IStorageManager.Stub
}
try {
- mVold.mountExternalStorageForApp(packageName, appId, sandboxId, userId);
+ mVold.prepareSandboxForApp(packageName, appId, sandboxId, userId);
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+
+ @Override
+ public void destroySandboxForApp(String packageName, int userId) {
+ if (!ENABLE_ISOLATED_STORAGE) {
+ return;
+ }
+ final int appId;
+ final String sandboxId;
+ synchronized (mPackagesLock) {
+ final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
+ userPackages.remove(packageName);
+ appId = mAppIds.get(packageName);
+ sandboxId = mSandboxIds.get(appId);
+
+ // If the package is not uninstalled in any other users, remove appId and sandboxId
+ // corresponding to it from the internal state.
+ boolean installedInAnyUser = false;
+ for (int i = mPackages.size() - 1; i >= 0; --i) {
+ if (mPackages.valueAt(i).contains(packageName)) {
+ installedInAnyUser = true;
+ break;
+ }
+ }
+ if (!installedInAnyUser) {
+ mAppIds.remove(packageName);
+ mSandboxIds.remove(appId);
+ }
+ }
+ try {
+ mVold.destroySandboxForApp(packageName, appId, sandboxId, userId);
} catch (Exception e) {
Slog.wtf(TAG, e);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fb8894b48411..591ec0070ea5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -49,6 +49,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.VoLteServiceState;
import android.util.LocalLog;
+import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -1719,8 +1720,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
mBatteryStats.notePhoneOff();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__OFF);
} else {
mBatteryStats.notePhoneOn();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__ON);
}
} catch (RemoteException e) {
/* The remote entity disappeared, we can safely ignore the exception. */
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a392b51d5f53..9c60b8c00019 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -6155,7 +6155,12 @@ public class AccountManagerService
final int uid;
try {
- uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ long identityToken = clearCallingIdentity();
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
} catch (NameNotFoundException e) {
Slog.e(TAG, "Unknown package " + packageName);
return;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8e64b5063302..f4ec1f9d5b27 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -25,7 +25,6 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -552,7 +551,7 @@ public final class ActiveServices {
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
- if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
+ if (proc == null || proc.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
@@ -580,7 +579,7 @@ public final class ActiveServices {
}
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
- } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
+ } else if (proc.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
@@ -589,7 +588,7 @@ public final class ActiveServices {
"Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
- sb.append("Not potential delay (state=").append(proc.curProcState)
+ sb.append("Not potential delay (state=").append(proc.getCurProcState())
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null) {
@@ -1442,8 +1441,8 @@ public final class ActiveServices {
}
}
}
- if (anyClientActivities != proc.hasClientActivities) {
- proc.hasClientActivities = anyClientActivities;
+ if (anyClientActivities != proc.hasClientActivities()) {
+ proc.setHasClientActivities(anyClientActivities);
if (updateLru) {
mAm.updateLruProcessLocked(proc, anyClientActivities, null);
}
@@ -1623,8 +1622,9 @@ public final class ActiveServices {
}
}
- mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
- s.appInfo.uid, s.appInfo.longVersionCode, s.name, s.processName);
+ mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+ callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
+ s.name, s.processName);
// Once the apps have become associated, if one of them is caller is ephemeral
// the target app should now be able to see the calling app
mAm.grantEphemeralAccessLocked(callerApp.userId, service,
@@ -1680,7 +1680,7 @@ public final class ActiveServices {
s.app.whitelistManager = true;
}
// This could have made the service more important.
- mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
+ mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities()
|| s.app.treatLikeActivity, b.client);
mAm.updateOomAdjLocked(s.app, true);
}
@@ -1794,7 +1794,7 @@ public final class ActiveServices {
if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
r.binding.service.app.treatLikeActivity = true;
mAm.updateLruProcessLocked(r.binding.service.app,
- r.binding.service.app.hasClientActivities
+ r.binding.service.app.hasClientActivities()
|| r.binding.service.app.treatLikeActivity, null);
}
mAm.updateOomAdjLocked(r.binding.service.app, false);
@@ -3259,9 +3259,9 @@ public final class ActiveServices {
}
}
- void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
+ void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
ArrayList<ServiceRecord> services = new ArrayList<>();
- ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(tr.userId);
+ ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(userId);
for (int i = alls.size() - 1; i >= 0; i--) {
ServiceRecord sr = alls.valueAt(i);
if (sr.packageName.equals(component.getPackageName())) {
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index a648b09abda5..fecb5732745e 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -37,12 +37,12 @@ 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.STACKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-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.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.TAG_STATES;
@@ -73,7 +73,7 @@ import java.util.ArrayList;
*/
class ActivityDisplay extends ConfigurationContainer<ActivityStack>
implements WindowContainerListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
static final int POSITION_TOP = Integer.MAX_VALUE;
@@ -1087,7 +1087,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
if (top == null) {
return false;
}
- mSupervisor.moveFocusableActivityToTop(top, reason);
+ top.moveFocusableActivityToTop(reason);
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
deleted file mode 100644
index f44ee7a234ca..000000000000
--- a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
+++ /dev/null
@@ -1,65 +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.server.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
-
-/**
- * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
- * inside {@link ActivityOptions#getLaunchBounds()}.
- */
-public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
- private final ActivityStackSupervisor mSupervisor;
-
- ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
- mSupervisor = activityStackSupervisor;
- }
-
- @Override
- public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source, ActivityOptions options,
- LaunchParams currentParams, LaunchParams outParams) {
- // We only care about figuring out bounds for activities.
- if (activity == null) {
- return RESULT_SKIP;
- }
-
- // Activity must be resizeable in the specified task.
- if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
- && (activity.isResizeable() || (task != null && task.isResizeable())))) {
- return RESULT_SKIP;
- }
-
- final Rect bounds = options.getLaunchBounds();
-
- // Bounds weren't valid.
- if (bounds == null || bounds.isEmpty()) {
- return RESULT_SKIP;
- }
-
- outParams.mBounds.set(bounds);
-
- // When this is the most explicit position specification so we should not allow further
- // modification of the position.
- return RESULT_DONE;
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 3a0289cbfd63..5c77f0a3ad47 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -220,7 +220,7 @@ final class ActivityManagerConstants extends ContentObserver {
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
- boolean mFlagActivityStartsLoggingEnabled;
+ volatile boolean mFlagActivityStartsLoggingEnabled;
private final ActivityManagerService mService;
private ContentResolver mResolver;
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 0e63d0c557f6..0aaea2f62de0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -41,97 +41,48 @@ class ActivityManagerDebugConfig {
// Enable all debug log categories.
static final boolean DEBUG_ALL = false;
- // Enable all debug log categories for activities.
- static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
-
// Available log categories in the activity manager package.
- static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_ANR = true; // STOPSHIP disable it (b/113252928)
- static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_BACKGROUND_CHECK = DEBUG_ALL || false;
static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
- static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
- static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
- static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_FOCUS = false;
- static final boolean DEBUG_IDLE = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
- static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ_REASON = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
static final boolean DEBUG_PSS = DEBUG_ALL || false;
- static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
- static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
- static final boolean DEBUG_RELEASE = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
- static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
- static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
- static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
- static final boolean DEBUG_TASKS = DEBUG_ALL || false;
- static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
- static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
- static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
static final boolean DEBUG_WHITELISTS = DEBUG_ALL || false;
- static final boolean DEBUG_METRICS = DEBUG_ALL || false;
- static final String POSTFIX_ADD_REMOVE = (APPEND_CATEGORY_NAME) ? "_AddRemove" : "";
- static final String POSTFIX_APP = (APPEND_CATEGORY_NAME) ? "_App" : "";
static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
static final String POSTFIX_CLEANUP = (APPEND_CATEGORY_NAME) ? "_Cleanup" : "";
- static final String POSTFIX_CONFIGURATION = (APPEND_CATEGORY_NAME) ? "_Configuration" : "";
- static final String POSTFIX_CONTAINERS = (APPEND_CATEGORY_NAME) ? "_Containers" : "";
- static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
- static final String POSTFIX_IDLE = (APPEND_CATEGORY_NAME) ? "_Idle" : "";
- static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
- static final String POSTFIX_LOCKTASK = (APPEND_CATEGORY_NAME) ? "_LockTask" : "";
static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
static final String POSTFIX_MU = "_MU";
static final String POSTFIX_NETWORK = "_Network";
static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
- static final String POSTFIX_PAUSE = (APPEND_CATEGORY_NAME) ? "_Pause" : "";
static final String POSTFIX_POWER = (APPEND_CATEGORY_NAME) ? "_Power" : "";
static final String POSTFIX_PROCESS_OBSERVERS = (APPEND_CATEGORY_NAME)
? "_ProcessObservers" : "";
static final String POSTFIX_PROCESSES = (APPEND_CATEGORY_NAME) ? "_Processes" : "";
static final String POSTFIX_PROVIDER = (APPEND_CATEGORY_NAME) ? "_Provider" : "";
static final String POSTFIX_PSS = (APPEND_CATEGORY_NAME) ? "_Pss" : "";
- static final String POSTFIX_RECENTS = (APPEND_CATEGORY_NAME) ? "_Recents" : "";
- static final String POSTFIX_RELEASE = (APPEND_CATEGORY_NAME) ? "_Release" : "";
- static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : "";
- static final String POSTFIX_SAVED_STATE = (APPEND_CATEGORY_NAME) ? "_SavedState" : "";
static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
static final String POSTFIX_SERVICE_EXECUTING =
(APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
- static final String POSTFIX_STACK = (APPEND_CATEGORY_NAME) ? "_Stack" : "";
- static final String POSTFIX_STATES = (APPEND_CATEGORY_NAME) ? "_States" : "";
- static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : "";
- static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
- static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
static final String POSTFIX_UID_OBSERVERS = (APPEND_CATEGORY_NAME)
? "_UidObservers" : "";
- static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
- static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
- static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
-
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37167c688d87..d5b618f954df 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -91,7 +91,6 @@ import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
@@ -100,9 +99,9 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
@@ -115,15 +114,15 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBS
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_NETWORK;
@@ -134,7 +133,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_O
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -202,7 +201,6 @@ import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy;
-import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
@@ -267,7 +265,6 @@ import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.Settings;
@@ -341,7 +338,6 @@ import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
-import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
@@ -434,7 +430,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final boolean MONITOR_THREAD_CPU_USAGE = false;
// The flags that are set for all calls we make to the package manager.
- static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
+ public static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
@@ -464,7 +460,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Must be kept in sync with Am.
private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
- static final int MY_PID = myPid();
+ public static final int MY_PID = myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -485,9 +481,6 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
"com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED";
- // Used to indicate that an app transition should be animated.
- static final boolean ANIMATE = true;
-
// If set, we will push process association information in to procstats.
static final boolean TRACK_PROCSTATS_ASSOCIATIONS = true;
@@ -1053,11 +1046,6 @@ public class ActivityManagerService extends IActivityManager.Stub
final AppOpsService mAppOpsService;
/**
- * Hardware-reported OpenGLES version.
- */
- final int GL_ES_VERSION;
-
- /**
* List of initialization arguments to pass to all processes when binding applications to them.
* For example, references to the commonly used services.
*/
@@ -1077,7 +1065,6 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this") boolean mCallFinishBooting = false;
@GuardedBy("this") boolean mBootAnimationComplete = false;
- private @GuardedBy("this") boolean mCheckedForSetup = false;
final Context mContext;
@@ -1405,7 +1392,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int SHOW_ERROR_UI_MSG = 1;
static final int SHOW_NOT_RESPONDING_UI_MSG = 2;
- static final int UPDATE_CONFIGURATION_MSG = 4;
static final int GC_BACKGROUND_PROCESSES_MSG = 5;
static final int WAIT_FOR_DEBUGGER_UI_MSG = 6;
static final int SERVICE_TIMEOUT_MSG = 12;
@@ -1420,7 +1406,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_PROCESS_DIED_UI_MSG = 32;
static final int REPORT_MEM_USAGE_MSG = 33;
static final int UPDATE_TIME_PREFERENCE_MSG = 41;
- static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
static final int DELETE_DUMPHEAP_MSG = 51;
@@ -1434,10 +1419,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
- static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
- static final int FIRST_COMPAT_MODE_MSG = 300;
- static final int FIRST_SUPERVISOR_STACK_MSG = 100;
static final String SERVICE_RECORD_KEY = "servicerecord";
@@ -1600,11 +1582,6 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case UPDATE_CONFIGURATION_MSG: {
- final ContentResolver resolver = mContext.getContentResolver();
- Settings.System.putConfigurationForUser(resolver, (Configuration) msg.obj,
- msg.arg1);
- } break;
case GC_BACKGROUND_PROCESSES_MSG: {
synchronized (ActivityManagerService.this) {
performAppGcsIfAppropriateLocked();
@@ -1735,18 +1712,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
break;
}
- case SEND_LOCALE_TO_MOUNT_DAEMON_MSG: {
- try {
- Locale l = (Locale) msg.obj;
- IBinder service = ServiceManager.getService("mount");
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
- storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
- } catch (RemoteException e) {
- Log.e(TAG, "Error storing locale for decryption UI", e);
- }
- break;
- }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
@@ -2058,6 +2023,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
mUsageStatsService = usageStatsManager;
+ mActivityTaskManager.setUsageStatsManager(usageStatsManager);
}
public void startObservingNativeCrashes() {
@@ -2297,7 +2263,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mInjector = injector;
mContext = mInjector.getContext();
mUiContext = null;
- GL_ES_VERSION = 0;
mAppErrors = null;
mAppOpsService = mInjector.getAppOpsService(null, null);
mBatteryStatsService = null;
@@ -2387,9 +2352,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mPendingIntentController = new PendingIntentController(
mHandlerThread.getLooper(), mUserController);
- GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
- ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
-
if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) {
mUseFifoUiScheduling = true;
}
@@ -2398,7 +2360,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mActivityTaskManager = atm;
- mActivityTaskManager.setActivityManagerService(this);
+ mActivityTaskManager.setActivityManagerService(this, mHandlerThread.getLooper(),
+ mIntentFirewall, mPendingIntentController);
mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mStackSupervisor = mActivityTaskManager.mStackSupervisor;
@@ -2834,7 +2797,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
- final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities
+ final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities()
|| app.treatLikeActivity;
final boolean hasService = false; // not impl yet. app.services.size() > 0;
if (!activityChange && hasActivity) {
@@ -3693,14 +3656,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- boolean getCheckedForSetup() {
- return mCheckedForSetup;
- }
-
- void setCheckedForSetup(boolean checked) {
- mCheckedForSetup = checked;
- }
-
CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
return mAtmInternal.compatibilityInfoForPackage(ai);
}
@@ -3764,7 +3719,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"Unable to set a higher trim level than current level");
}
if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
- app.curProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
+ app.getCurProcState() > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
throw new IllegalArgumentException("Unable to set a background trim level "
+ "on a foreground process");
}
@@ -6550,7 +6505,7 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i = 0; i < pids.length; i++) {
ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
states[i] = (pr == null) ? ActivityManager.PROCESS_STATE_NONEXISTENT :
- pr.curProcState;
+ pr.getCurProcState();
if (scores != null) {
scores[i] = (pr == null) ? ProcessList.INVALID_ADJ : pr.curAdj;
}
@@ -6834,7 +6789,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proc = mPidsSelfLocked.get(callingPid);
}
if (proc != null &&
- !ActivityManager.isProcStateBackground(proc.curProcState)) {
+ !ActivityManager.isProcStateBackground(proc.getCurProcState())) {
// Whoever is instigating this is in the foreground, so we will allow it
// to go through.
return ActivityManager.APP_START_MODE_NORMAL;
@@ -6871,11 +6826,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return ptw != null ? ptw.tag : null;
}
- @VisibleForTesting
- boolean isActivityStartsLoggingEnabled() {
- return mConstants.mFlagActivityStartsLoggingEnabled;
- }
-
private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) {
ProviderInfo pi = null;
ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle);
@@ -7415,7 +7365,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
cpr.connections.add(conn);
r.conProviders.add(conn);
- startAssociationLocked(r.uid, r.processName, r.curProcState,
+ startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
return conn;
}
@@ -9250,11 +9200,11 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, "setHasTopUi called on unknown pid: " + pid);
return;
}
- if (pr.hasTopUi != hasTopUi) {
+ if (pr.hasTopUi() != hasTopUi) {
if (DEBUG_OOM_ADJ) {
Slog.d(TAG, "Setting hasTopUi=" + hasTopUi + " for pid=" + pid);
}
- pr.hasTopUi = hasTopUi;
+ pr.setHasTopUi(hasTopUi);
changed = true;
}
}
@@ -10184,6 +10134,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
sb.append("Process: ").append(processName).append("\n");
sb.append("PID: ").append(process.pid).append("\n");
+ sb.append("UID: ").append(process.uid).append("\n");
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
@@ -10434,10 +10385,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
outInfo.lastTrimLevel = app.trimMemoryLevel;
int adj = app.curAdj;
- int procState = app.curProcState;
+ int procState = app.getCurProcState();
outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk);
outInfo.importanceReasonCode = app.adjTypeCode;
- outInfo.processState = app.curProcState;
+ outInfo.processState = app.getCurProcState();
outInfo.isFocused = (app == getTopAppLocked());
outInfo.lastActivityTime = app.lastActivityTime;
}
@@ -12661,12 +12612,13 @@ public class ActivityManagerService extends IActivityManager.Stub
if (schedGroup != ProcessOomProto.SCHED_GROUP_UNKNOWN) {
proto.write(ProcessOomProto.SCHED_GROUP, schedGroup);
}
- if (r.foregroundActivities) {
+ if (r.hasForegroundActivities()) {
proto.write(ProcessOomProto.ACTIVITIES, true);
} else if (r.hasForegroundServices()) {
proto.write(ProcessOomProto.SERVICES, true);
}
- proto.write(ProcessOomProto.STATE, ProcessList.makeProcStateProtoEnum(r.curProcState));
+ proto.write(ProcessOomProto.STATE,
+ ProcessList.makeProcStateProtoEnum(r.getCurProcState()));
proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.trimMemoryLevel);
r.writeToProto(proto, ProcessOomProto.PROC);
proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
@@ -12692,7 +12644,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.write(ProcessOomProto.Detail.CUR_ADJ, r.curAdj);
proto.write(ProcessOomProto.Detail.SET_ADJ, r.setAdj);
proto.write(ProcessOomProto.Detail.CURRENT_STATE,
- ProcessList.makeProcStateProtoEnum(r.curProcState));
+ ProcessList.makeProcStateProtoEnum(r.getCurProcState()));
proto.write(ProcessOomProto.Detail.SET_STATE,
ProcessList.makeProcStateProtoEnum(r.setProcState));
proto.write(ProcessOomProto.Detail.LAST_PSS, DebugUtils.sizeValueToString(
@@ -12758,14 +12710,14 @@ public class ActivityManagerService extends IActivityManager.Stub
break;
}
char foreground;
- if (r.foregroundActivities) {
+ if (r.hasForegroundActivities()) {
foreground = 'A';
} else if (r.hasForegroundServices()) {
foreground = 'S';
} else {
foreground = ' ';
}
- String procState = ProcessList.makeProcStateString(r.curProcState);
+ String procState = ProcessList.makeProcStateString(r.getCurProcState());
pw.print(prefix);
pw.print(r.isPersistent() ? persistentLabel : normalLabel);
pw.print(" #");
@@ -12819,7 +12771,8 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(" set="); pw.println(r.setAdj);
pw.print(prefix);
pw.print(" ");
- pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
+ pw.print("state: cur="); pw.print(
+ ProcessList.makeProcStateString(r.getCurProcState()));
pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, r.lastSwapPss*1024);
@@ -14609,11 +14562,11 @@ public class ActivityManagerService extends IActivityManager.Stub
app.waitingToKill = null;
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
- app.foregroundActivities = false;
+ app.setHasForegroundActivities(false);
app.hasShownUi = false;
app.treatLikeActivity = false;
app.hasAboveClient = false;
- app.hasClientActivities = false;
+ app.setHasClientActivities(false);
mServices.killServicesLocked(app, allowRestart);
@@ -17055,7 +17008,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
- app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+ app.setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
app.completedAdjSeq = app.adjSeq;
return false;
@@ -17072,7 +17025,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final int logUid = mCurOomAdjUid;
int prevAppAdj = app.curAdj;
- int prevProcState = app.curProcState;
+ int prevProcState = app.getCurProcState();
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
@@ -17083,9 +17036,9 @@ public class ActivityManagerService extends IActivityManager.Stub
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
- app.foregroundActivities = false;
+ app.setHasForegroundActivities(false);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
- app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
+ app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
@@ -17095,7 +17048,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.systemNoUi = false;
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
app.adjType = "pers-top-activity";
- } else if (app.hasTopUi) {
+ } else if (app.hasTopUi()) {
// sched group/proc state adjustment is below
app.systemNoUi = false;
app.adjType = "pers-top-ui";
@@ -17105,11 +17058,11 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!app.systemNoUi) {
if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
// screen on, promote UI
- app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+ app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
} else {
// screen off, restrict UI scheduling
- app.curProcState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
}
}
@@ -17245,7 +17198,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to fg service: " + app);
}
- } else if (app.hasOverlayUi) {
+ } else if (app.hasOverlayUi()) {
// The process is display an overlay UI.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
@@ -17475,7 +17428,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
int clientAdj = client.curRawAdj;
- int clientProcState = client.curProcState;
+ int clientProcState = client.getCurProcState();
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty. The specific cached state
@@ -17636,8 +17589,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
- app.pendingUiClean = true;
+ && (cr.flags & Context.BIND_SHOWING_UI) != 0) {
+ app.setPendingUiClean(true);
}
if (adjType != null) {
app.adjType = adjType;
@@ -17717,7 +17670,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
int clientAdj = client.curRawAdj;
- int clientProcState = client.curProcState;
+ int clientProcState = client.getCurProcState();
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
// we are going to consider it empty.
@@ -17878,7 +17831,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- if (app.hasClientActivities) {
+ if (app.hasClientActivities()) {
// This is a cached process, but with client activities. Mark it so.
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
app.adjType = "cch-client-act";
@@ -17945,12 +17898,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// keep it out of the cached vaues.
app.curAdj = app.modifyRawOomAdj(adj);
app.setCurrentSchedulingGroup(schedGroup);
- app.curProcState = procState;
- app.foregroundActivities = foregroundActivities;
+ app.setCurProcState(procState);
+ app.setHasForegroundActivities(foregroundActivities);
app.completedAdjSeq = mAdjSeq;
// if curAdj or curProcState improved, then this process was promoted
- return app.curAdj < prevAppAdj || app.curProcState < prevProcState;
+ return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
}
/**
@@ -18102,7 +18055,7 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (app.thread == null
- || app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ || app.getCurProcState() == ActivityManager.PROCESS_STATE_NONEXISTENT) {
continue;
}
if (memLowered || (always && now >
@@ -18111,7 +18064,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.pssProcState = app.setProcState;
app.pssStatType = always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
: ProcessStats.ADD_PSS_INTERNAL_ALL_MEM;
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
app.procStateMemTracker, mTestPssMode, mAtmInternal.isSleeping(), now);
mPendingPssProcesses.add(app);
}
@@ -18304,7 +18257,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (doCpuKills && uptimeSince > 0) {
// What is the limit for this process?
int cpuLimit;
- long checkDur = curUptime - app.whenUnimportant;
+ long checkDur = curUptime - app.getWhenUnimportant();
if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;
} else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*2)
@@ -18466,12 +18419,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
- if (app.repForegroundActivities != app.foregroundActivities) {
- app.repForegroundActivities = app.foregroundActivities;
+ if (app.repForegroundActivities != app.hasForegroundActivities()) {
+ app.repForegroundActivities = app.hasForegroundActivities();
changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
}
- if (app.getReportedProcState() != app.curProcState) {
- app.setReportedProcState(app.curProcState);
+ if (app.getReportedProcState() != app.getCurProcState()) {
+ app.setReportedProcState(app.getCurProcState());
if (app.thread != null) {
try {
if (false) {
@@ -18485,7 +18438,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
if (app.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT
- || ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) {
+ || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
// Experimental code to more aggressively collect pss while
// running test... the problem is that this tends to collect
@@ -18495,46 +18448,45 @@ public class ActivityManagerService extends IActivityManager.Stub
long startTime = SystemClock.currentThreadTimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
long endTime = SystemClock.currentThreadTimeMillis();
- recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1],
+ recordPssSampleLocked(app, app.getCurProcState(), pss, mTmpLong[0], mTmpLong[1],
mTmpLong[2], ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
- + " to " + app.curProcState + ": "
+ + " to " + app.getCurProcState() + ": "
+ (SystemClock.uptimeMillis()-start) + "ms");
}
app.lastStateTime = now;
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
app.procStateMemTracker, mTestPssMode, mAtmInternal.isSleeping(), now);
if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
- + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
+ + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
+ (app.nextPssTime-now) + ": " + app);
} else {
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
mTestPssMode)))) {
if (requestPssLocked(app, app.setProcState)) {
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
app.procStateMemTracker, mTestPssMode, mAtmInternal.isSleeping(), now);
}
} else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
"Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
}
- if (app.setProcState != app.curProcState) {
+ if (app.setProcState != app.getCurProcState()) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
String msg = "Proc state change of " + app.processName
- + " to " + ProcessList.makeProcStateString(app.curProcState)
- + " (" + app.curProcState + ")" + ": " + app.adjType;
+ + " to " + ProcessList.makeProcStateString(app.getCurProcState())
+ + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
}
boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
- boolean curImportant = app.curProcState < ActivityManager.PROCESS_STATE_SERVICE;
+ boolean curImportant = app.getCurProcState() < ActivityManager.PROCESS_STATE_SERVICE;
if (setImportant && !curImportant) {
- // This app is no longer something we consider important enough to allow to
- // use arbitrary amounts of battery power. Note
- // its current CPU time to later know to kill it if
- // it is not behaving well.
- app.whenUnimportant = now;
+ // This app is no longer something we consider important enough to allow to use
+ // arbitrary amounts of battery power. Note its current CPU time to later know to
+ // kill it if it is not behaving well.
+ app.setWhenUnimportant(now);
app.lastCpuTime = 0;
}
// Inform UsageStats of important process state change
@@ -18543,7 +18495,7 @@ public class ActivityManagerService extends IActivityManager.Stub
maybeUpdateLastTopTime(app, now);
- app.setProcState = app.curProcState;
+ app.setProcState = app.getCurProcState();
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
app.notCachedSinceIdle = false;
}
@@ -18552,7 +18504,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
app.procStateChanged = true;
}
- } else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime)
+ } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
> mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
// For apps that sit around for a long time in the interactive state, we need
// to report this at least once a day so they don't go idle.
@@ -18706,7 +18658,7 @@ public class ActivityManagerService extends IActivityManager.Stub
private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
String authority) {
if (app == null) return;
- if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
UserState userState = mUserController.getStartedUserState(app.userId);
if (userState == null) return;
final long now = SystemClock.elapsedRealtime();
@@ -18726,7 +18678,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_USAGE_STATS) {
Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
+ "] state changes: old = " + app.setProcState + ", new = "
- + app.curProcState);
+ + app.getCurProcState());
}
if (mUsageStatsService == null) {
return;
@@ -18735,24 +18687,26 @@ public class ActivityManagerService extends IActivityManager.Stub
// To avoid some abuse patterns, we are going to be careful about what we consider
// to be an app interaction. Being the top activity doesn't count while the display
// is sleeping, nor do short foreground services.
- if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP) {
+ if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP) {
isInteraction = true;
- app.fgInteractionTime = 0;
- } else if (app.curProcState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
- if (app.fgInteractionTime == 0) {
- app.fgInteractionTime = nowElapsed;
+ app.setFgInteractionTime(0);
+ } else if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ if (app.getFgInteractionTime() == 0) {
+ app.setFgInteractionTime(nowElapsed);
isInteraction = false;
} else {
- isInteraction = nowElapsed > app.fgInteractionTime
+ isInteraction = nowElapsed > app.getFgInteractionTime()
+ mConstants.SERVICE_USAGE_INTERACTION_TIME;
}
} else {
- isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
- app.fgInteractionTime = 0;
+ isInteraction =
+ app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ app.setFgInteractionTime(0);
}
- if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
+ if (isInteraction
+ && (!app.reportedInteraction || (nowElapsed - app.getInteractionEventTime())
> mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
- app.interactionEventTime = nowElapsed;
+ app.setInteractionEventTime(nowElapsed);
String[] packages = app.getPackageList();
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
@@ -18763,13 +18717,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app.reportedInteraction = isInteraction;
if (!isInteraction) {
- app.interactionEventTime = 0;
+ app.setInteractionEventTime(0);
}
}
private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
- && app.curProcState > ActivityManager.PROCESS_STATE_TOP) {
+ && app.getCurProcState() > ActivityManager.PROCESS_STATE_TOP) {
app.lastTopTime = nowUptime;
}
}
@@ -18990,7 +18944,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// If we haven't yet assigned the final cached adj
// to the process, do that now.
if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
- switch (app.curProcState) {
+ switch (app.getCurProcState()) {
case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
@@ -19078,7 +19032,7 @@ public class ActivityManagerService extends IActivityManager.Stub
applyOomAdjLocked(app, true, now, nowElapsed);
// Count the number of process types.
- switch (app.curProcState) {
+ switch (app.getCurProcState()) {
case PROCESS_STATE_CACHED_ACTIVITY:
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
@@ -19119,8 +19073,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final UidRecord uidRec = app.uidRecord;
if (uidRec != null) {
uidRec.ephemeral = app.info.isInstantApp();
- if (uidRec.curProcState > app.curProcState) {
- uidRec.curProcState = app.curProcState;
+ if (uidRec.curProcState > app.getCurProcState()) {
+ uidRec.curProcState = app.getCurProcState();
}
if (app.hasForegroundServices()) {
uidRec.foregroundServices = true;
@@ -19128,7 +19082,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
+ if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
numTrimming++;
}
@@ -19211,7 +19165,7 @@ public class ActivityManagerService extends IActivityManager.Stub
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
- if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
+ if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
@@ -19234,7 +19188,7 @@ public class ActivityManagerService extends IActivityManager.Stub
break;
}
}
- } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ } else if (app.getCurProcState() == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
&& !app.killedByAm) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
@@ -19249,8 +19203,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {
- if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- || app.systemNoUi) && app.pendingUiClean) {
+ if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || app.systemNoUi) && app.hasPendingUiClean()) {
// If this application is now in the background and it
// had done UI, then give it the special trim level to
// have it free UI resources.
@@ -19264,7 +19218,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} catch (RemoteException e) {
}
}
- app.pendingUiClean = false;
+ app.setPendingUiClean(false);
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
@@ -19289,8 +19243,8 @@ public class ActivityManagerService extends IActivityManager.Stub
setProcessTrackerStateLocked(app, trackerMemFactor, now);
app.procStateChanged = false;
}
- if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- || app.systemNoUi) && app.pendingUiClean) {
+ if ((app.getCurProcState() >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || app.systemNoUi) && app.hasPendingUiClean()) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
@@ -19302,7 +19256,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} catch (RemoteException e) {
}
}
- app.pendingUiClean = false;
+ app.setPendingUiClean(false);
}
app.trimMemoryLevel = 0;
}
@@ -20319,7 +20273,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.removed) {
procs.add(app);
- } else if (app.userId == userHandle && app.foregroundActivities) {
+ } else if (app.userId == userHandle && app.hasForegroundActivities()) {
app.removed = true;
procs.add(app);
}
@@ -20390,10 +20344,10 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
}
- if (pr.hasOverlayUi == hasOverlayUi) {
+ if (pr.hasOverlayUi() == hasOverlayUi) {
return;
}
- pr.hasOverlayUi = hasOverlayUi;
+ pr.setHasOverlayUi(hasOverlayUi);
//Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
updateOomAdjLocked(pr, true);
}
@@ -20778,6 +20732,42 @@ public class ActivityManagerService extends IActivityManager.Stub
(ConnectionRecord) cr, null, c));
}
}
+
+ public void cleanUpServices(int userId, ComponentName component, Intent baseIntent) {
+ synchronized(ActivityManagerService.this) {
+ mServices.cleanUpServices(userId, component, baseIntent);
+ }
+ }
+
+ public ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
+ // Locked intentionally not held as it isn't needed for this case.
+ return ActivityManagerService.this.getActivityInfoForUser(aInfo, userId);
+ }
+
+ public void ensureBootCompleted() {
+ // Locked intentionally not held as it isn't needed for this case.
+ ActivityManagerService.this.ensureBootCompleted();
+ }
+
+ public void updateOomLevelsForDisplay(int displayId) {
+ synchronized(ActivityManagerService.this) {
+ if (mWindowManager != null) {
+ mProcessList.applyDisplaySize(mWindowManager);
+ }
+ }
+ }
+
+ public boolean isActivityStartsLoggingEnabled() {
+ return mConstants.mFlagActivityStartsLoggingEnabled;
+ }
+
+ public void reportCurKeyguardUsageEvent(boolean keyguardShowing) {
+ synchronized(ActivityManagerService.this) {
+ ActivityManagerService.this.reportGlobalUsageEventLocked(keyguardShowing
+ ? UsageEvents.Event.KEYGUARD_SHOWN
+ : UsageEvents.Event.KEYGUARD_HIDDEN);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 40c555f8c2e6..9f768a84d223 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -23,7 +23,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import android.app.ActivityManager;
import android.app.ActivityOptions;
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 18cdb054e648..2620e1e85565 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -72,9 +72,9 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
-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.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
@@ -110,11 +110,11 @@ import com.android.server.LocalServices;
* data for Tron, logcat, event logs and {@link android.app.WaitResult}.
*
* Tests:
- * atest SystemMetricsFunctionalTests
+ * atest CtsActivityManagerDeviceTestCases:ActivityMetricsLoggerTests
*/
class ActivityMetricsLogger {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_ATM;
// Window modes we are interested in logging. If we ever introduce a new type, we need to add
// a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
@@ -230,14 +230,14 @@ class ActivityMetricsLogger {
launchedActivityLaunchToken = launchedActivity.info.launchToken;
launchedActivityAppRecordRequiredAbi = launchedActivity.app == null
? null
- : info.launchedActivity.app.getRequiredAbi();
+ : launchedActivity.app.getRequiredAbi();
reason = info.reason;
startingWindowDelayMs = info.startingWindowDelayMs;
bindApplicationDelayMs = info.bindApplicationDelayMs;
windowsDrawnDelayMs = info.windowsDrawnDelayMs;
type = getTransitionType(info);
- processRecord = findProcessForActivity(info.launchedActivity);
- processName = info.launchedActivity.processName;
+ processRecord = findProcessForActivity(launchedActivity);
+ processName = launchedActivity.processName;
userId = launchedActivity.userId;
launchedActivityShortComponentName = launchedActivity.shortComponentName;
activityRecordIdHashCode = System.identityHashCode(launchedActivity);
@@ -351,18 +351,24 @@ class ActivityMetricsLogger {
+ " processRunning=" + processRunning
+ " processSwitch=" + processSwitch);
- // If we are already in an existing transition, only update the activity name, but not the
- // other attributes.
final int windowingMode = launchedActivity != null
? launchedActivity.getWindowingMode()
: WINDOWING_MODE_UNDEFINED;
-
+ final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (mCurrentTransitionStartTime == INVALID_START_TIME) {
+ // No transition is active ignore this launch.
+ return;
+ }
+
+ if (launchedActivity != null && launchedActivity.nowVisible) {
+ // Launched activity is already visible. We cannot measure windows drawn delay.
+ reset(true /* abort */, info);
return;
}
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (launchedActivity != null && info != null) {
+ // If we are already in an existing transition, only update the activity name, but not
+ // the other attributes.
info.launchedActivity = launchedActivity;
return;
}
@@ -371,7 +377,6 @@ class ActivityMetricsLogger {
mWindowingModeTransitionInfo.size() > 0 && info == null;
if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
-
// Failed to launch or it was not a process switch, so we don't care about the timing.
reset(true /* abort */, info);
return;
@@ -736,7 +741,7 @@ class ActivityMetricsLogger {
Log.i(TAG, sb.toString());
}
- void logActivityStart(Intent intent, ProcessRecord callerApp, ActivityRecord r,
+ void logActivityStart(Intent intent, WindowProcessController callerApp, ActivityRecord r,
int callingUid, String callingPackage, int callingUidProcState,
boolean callingUidHasAnyVisibleWindow,
int realCallingUid, int realCallingUidProcState,
@@ -771,31 +776,31 @@ class ActivityMetricsLogger {
builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
if (callerApp != null) {
- builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.processName);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.mName);
builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE,
- processStateAmToProto(callerApp.curProcState));
+ processStateAmToProto(callerApp.getCurrentProcState()));
builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES,
- callerApp.hasClientActivities ? 1 : 0);
+ callerApp.hasClientActivities() ? 1 : 0);
builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES,
callerApp.hasForegroundServices() ? 1 : 0);
builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES,
- callerApp.foregroundActivities ? 1 : 0);
- builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi ? 1 : 0);
+ callerApp.hasForegroundActivities() ? 1 : 0);
+ builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi() ? 1 : 0);
builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_OVERLAY_UI,
- callerApp.hasOverlayUi ? 1 : 0);
+ callerApp.hasOverlayUi() ? 1 : 0);
builder.addTaggedData(FIELD_PROCESS_RECORD_PENDING_UI_CLEAN,
- callerApp.pendingUiClean ? 1 : 0);
- if (callerApp.interactionEventTime != 0) {
+ callerApp.hasPendingUiClean() ? 1 : 0);
+ if (callerApp.getInteractionEventTime() != 0) {
builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT,
- (nowElapsed - callerApp.interactionEventTime));
+ (nowElapsed - callerApp.getInteractionEventTime()));
}
- if (callerApp.fgInteractionTime != 0) {
+ if (callerApp.getFgInteractionTime() != 0) {
builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION,
- (nowElapsed - callerApp.fgInteractionTime));
+ (nowElapsed - callerApp.getFgInteractionTime()));
}
- if (callerApp.whenUnimportant != 0) {
+ if (callerApp.getWhenUnimportant() != 0) {
builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT,
- (nowUptime - callerApp.whenUnimportant));
+ (nowUptime - callerApp.getWhenUnimportant()));
}
}
builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fe10baf33354..d837118f05d4 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -83,18 +83,20 @@ import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-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.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
@@ -116,7 +118,7 @@ import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.am.TaskPersister.DEBUG;
import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -209,12 +211,13 @@ import java.util.Objects;
* An entry in the history stack, representing an activity.
*/
final class ActivityRecord extends ConfigurationContainer implements AppWindowContainerListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
// TODO(b/67864419): Remove once recents component is overridden
private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
@@ -849,13 +852,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
}
- ActivityRecord(ActivityTaskManagerService _service, ProcessRecord _caller, int _launchedFromPid,
- int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
- ActivityInfo aInfo, Configuration _configuration,
- ActivityRecord _resultTo, String _resultWho, int _reqCode,
- boolean _componentSpecified, boolean _rootVoiceInteraction,
- ActivityStackSupervisor supervisor, ActivityOptions options,
- ActivityRecord sourceRecord) {
+ ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
+ int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent,
+ String _resolvedType, ActivityInfo aInfo, Configuration _configuration,
+ ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified,
+ boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor,
+ ActivityOptions options, ActivityRecord sourceRecord) {
service = _service;
appToken = new Token(this, _intent);
info = aInfo;
@@ -925,8 +927,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
&& (aInfo.applicationInfo.uid == SYSTEM_UID
- || aInfo.applicationInfo.uid == _caller.info.uid)) {
- processName = _caller.processName;
+ || aInfo.applicationInfo.uid == _caller.mInfo.uid)) {
+ processName = _caller.mName;
} else {
processName = aInfo.processName;
}
@@ -1348,6 +1350,42 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
+ /** Move activity with its stack to front and make the stack focused. */
+ boolean moveFocusableActivityToTop(String reason) {
+ if (!isFocusable()) {
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
+ }
+ return false;
+ }
+
+ final TaskRecord task = getTask();
+ final ActivityStack stack = getStack();
+ if (stack == null) {
+ Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
+ + this + " task=" + task);
+ return false;
+ }
+
+ if (mStackSupervisor.getTopResumedActivity() == this) {
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
+ }
+ return false;
+ }
+
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
+ }
+
+ stack.moveToFront(reason, task);
+ // Report top activity change to tracking services and WM
+ if (mStackSupervisor.getTopResumedActivity() == this) {
+ // TODO(b/111361570): Support multiple focused apps in WM
+ service.setResumedActivityUncheckLocked(this, reason);
+ }
+ return true;
+ }
/**
* @return true if the activity contains windows that have
@@ -1744,7 +1782,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
setVisible(true);
sleeping = false;
- app.setPendingUiClean(true);
+ app.postPendingUiCleanMsg(true);
if (reportToClient) {
makeClientVisible();
} else {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6388423d04b4..d6a47d8951d5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -48,39 +48,39 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
import static com.android.server.am.ActivityDisplay.POSITION_TOP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TRANSITION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_APP;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_APP;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_APP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TRANSITION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-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.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
@@ -103,6 +103,7 @@ import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.am.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
import static java.lang.Integer.MAX_VALUE;
import android.app.Activity;
@@ -172,7 +173,7 @@ import java.util.Set;
*/
class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
implements StackWindowListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
@@ -227,7 +228,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
@Override
- protected ConfigurationContainer getChildAt(int index) {
+ protected TaskRecord getChildAt(int index) {
return mTaskHistory.get(index);
}
@@ -364,12 +365,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
private boolean mTopActivityOccludesKeyguard;
private ActivityRecord mTopDismissingKeyguardActivity;
- static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
- static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
- static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
- static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
- static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
- static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
+ static final int PAUSE_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
+ static final int DESTROY_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 2;
+ static final int LAUNCH_TICK_MSG = FIRST_ACTIVITY_STACK_MSG + 3;
+ static final int STOP_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 4;
+ static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
+ static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
private static class ScheduleDestroyArgs {
final WindowProcessController mOwner;
@@ -3450,8 +3451,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final String myReason = reason + " adjustFocus";
if (next == r) {
- mStackSupervisor.moveFocusableActivityToTop(mStackSupervisor.topRunningActivityLocked(),
- myReason);
+ final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+ if (top != null) {
+ top.moveFocusableActivityToTop(myReason);
+ }
return;
}
@@ -4662,7 +4665,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Set focus to the top running activity of this stack.
final ActivityRecord r = topRunningActivityLocked();
- mStackSupervisor.moveFocusableActivityToTop(r, reason);
+ if (r != null) {
+ r.moveFocusableActivityToTop(reason);
+ }
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0477d73301f1..3f823ae8c631 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -53,29 +53,28 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-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.ANIMATE;
-import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.am.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_NONE;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
@@ -92,13 +91,14 @@ import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS
import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+
import static java.lang.Integer.MAX_VALUE;
import android.Manifest;
@@ -198,8 +198,7 @@ import java.util.Set;
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
RecentTasks.Callbacks, RootWindowContainerListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
- private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_ATM;
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -783,7 +782,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
- moveFocusableActivityToTop(r, myReason);
+ r.moveFocusableActivityToTop(myReason);
return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser, myReason, displayId);
@@ -1488,7 +1487,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
app.hasShownUi = true;
- app.pendingUiClean = true;
+ app.setPendingUiClean(true);
app.forceProcessStateUpTo(mService.mTopProcessState);
// Because we could be starting an Activity in the system process this may not go
// across a Binder interface which would create a new Configuration. Consequently
@@ -1718,24 +1717,25 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
sendHint = noResumedActivities || allFocusedProcessesDiffer;
}
- if (sendHint && mService.mAm.mLocalPowerManager != null) {
- mService.mAm.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
+ if (sendHint && mService.mPowerManagerInternal != null) {
+ mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 1);
mPowerHintSent = true;
}
}
void sendPowerHintForLaunchEndIfNeeded() {
// Trigger launch power hint if activity is launched
- if (mPowerHintSent && mService.mAm.mLocalPowerManager != null) {
- mService.mAm.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
+ if (mPowerHintSent && mService.mPowerManagerInternal != null) {
+ mService.mPowerManagerInternal.powerHint(PowerHint.LAUNCH, 0);
mPowerHintSent = false;
}
}
- boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
- String resultWho, int requestCode, int callingPid, int callingUid,
- String callingPackage, boolean ignoreTargetSecurity, boolean launchingInTask,
- ProcessRecord callerApp, ActivityRecord resultRecord, ActivityStack resultStack) {
+ boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho,
+ int requestCode, int callingPid, int callingUid, String callingPackage,
+ boolean ignoreTargetSecurity, boolean launchingInTask,
+ WindowProcessController callerApp, ActivityRecord resultRecord,
+ ActivityStack resultStack) {
final boolean isCallerRecents = mService.getRecentTasks() != null
&& mService.getRecentTasks().isCallerRecents(callingUid);
final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
@@ -3073,7 +3073,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Find any running services associated with this app and stop if needed.
- mService.mAm.mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
+ final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
+ mService.mAmInternal, tr.userId, component, new Intent(tr.getBaseIntent()));
+ mService.mH.sendMessage(msg);
if (!killProcess) {
return;
@@ -3359,41 +3361,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService.getTaskChangeNotificationController().notifyActivityPinned(r);
}
- /** Move activity with its stack to front and make the stack focused. */
- // TODO(b/111363427): Move this method to ActivityRecord.
- boolean moveFocusableActivityToTop(ActivityRecord r, String reason) {
- if (r == null || !r.isFocusable()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: unfocusable r=" + r);
- return false;
- }
-
- final TaskRecord task = r.getTask();
- final ActivityStack stack = r.getStack();
- if (stack == null) {
- Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
- + r + " task=" + task);
- return false;
- }
-
- if (r == getTopResumedActivity()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: already on top, r=" + r);
- return false;
- }
-
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: r=" + r);
-
- stack.moveToFront(reason, task);
- // Report top activity change to tracking services and WM
- if (r == getTopResumedActivity()) {
- // TODO(b/111361570): Support multiple focused apps in WM
- mService.setResumedActivityUncheckLocked(r, reason);
- }
- return true;
- }
-
ActivityRecord findTaskLocked(ActivityRecord r, int preferredDisplayId) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
mTmpFindTaskResult.clear();
@@ -3458,7 +3425,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivity.release();
- mService.mAm.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
+ mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
}
}
@@ -4456,10 +4423,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
throw new IllegalStateException("Task resolved to incompatible display");
}
- // The task might have landed on a display different from requested.
- // TODO(multi-display): Find proper stack for the task on the default display.
- mService.setTaskWindowingMode(task.taskId,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */);
if (preferredDisplayId != actualDisplayId) {
Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
// Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index f6f1e5508957..20d5ab201307 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -22,8 +22,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
-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.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -65,7 +65,7 @@ import java.util.List;
* through the pending activity list, and recording home activity launches.
*/
public class ActivityStartController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStartController" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStartController" : TAG_ATM;
private static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 1;
@@ -91,6 +91,8 @@ public class ActivityStartController {
private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry;
+ boolean mCheckedForSetup = false;
+
private final class StartHandler extends Handler {
public StartHandler(Looper looper) {
super(looper, null, true);
@@ -193,7 +195,7 @@ public class ActivityStartController {
*/
void startSetupActivity() {
// Only do this once per boot.
- if (mService.mAm.getCheckedForSetup()) {
+ if (mCheckedForSetup) {
return;
}
@@ -203,7 +205,7 @@ public class ActivityStartController {
final ContentResolver resolver = mService.mContext.getContentResolver();
if (mService.mFactoryTest != FACTORY_TEST_LOW_LEVEL
&& Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
- mService.mAm.setCheckedForSetup(true);
+ mCheckedForSetup = true;
// See if we should be showing the platform update setup UI.
final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
@@ -357,7 +359,7 @@ public class ActivityStartController {
null, userId, ActivityStarter.computeResolveFilterUid(
callingUid, realCallingUid, UserHandle.USER_NULL));
// TODO: New, check if this is correct
- aInfo = mService.mAm.getActivityInfoForUser(aInfo, userId);
+ aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 4789ff334398..e51824f6f790 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -44,6 +44,7 @@ import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -246,9 +247,9 @@ class ActivityStartInterceptor {
if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
return interceptSuspendedByAdminPackage();
}
- final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
+ final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, mUserId);
mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
- suspendingPackage, dialogMessage, mUserId);
+ suspendingPackage, dialogInfo, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2bd22e8601d6..c92e48fd5f1a 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -53,20 +53,20 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
-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.ANIMATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -127,7 +127,7 @@ import java.util.Date;
* an activity and associated task and stack.
*/
class ActivityStarter {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_ATM;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
@@ -590,12 +590,12 @@ class ActivityStarter {
final Bundle verificationBundle
= options != null ? options.popAppVerificationBundle() : null;
- ProcessRecord callerApp = null;
+ WindowProcessController callerApp = null;
if (caller != null) {
- callerApp = mService.mAm.getRecordForAppLocked(caller);
+ callerApp = mService.getProcessController(caller);
if (callerApp != null) {
- callingPid = callerApp.pid;
- callingUid = callerApp.info.uid;
+ callingPid = callerApp.getPid();
+ callingUid = callerApp.mInfo.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
@@ -726,14 +726,12 @@ class ActivityStarter {
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
inTask != null, callerApp, resultRecord, resultStack);
- abort |= !mService.mAm.mIntentFirewall.checkStartActivity(intent, callingUid,
+ abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
- final WindowProcessController callerWpc =
- callerApp != null ? callerApp.getWindowProcessController() : null;
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
- ? options.getOptions(intent, aInfo, callerWpc, mSupervisor) : null;
+ ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
if (allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
@@ -833,8 +831,7 @@ class ActivityStarter {
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
- ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid,
- callingUid,
+ ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);
@@ -857,7 +854,7 @@ class ActivityStarter {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
- sourceRecord, startFlags, stack, callerWpc));
+ sourceRecord, startFlags, stack, callerApp));
ActivityOptions.abort(checkedOptions);
return ActivityManager.START_SWITCHES_CANCELED;
}
@@ -874,12 +871,11 @@ class ActivityStarter {
}
private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
- Intent intent, ProcessRecord callerApp, ActivityRecord r,
+ Intent intent, WindowProcessController callerApp, ActivityRecord r,
PendingIntentRecord originatingPendingIntent) {
- boolean callerAppHasForegroundActivity = (callerApp != null)
- ? callerApp.foregroundActivities
- : false;
- if (!mService.mAm.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity
+ boolean callerAppHasForegroundActivity =
+ callerApp != null && callerApp.hasForegroundActivities();
+ if (!mService.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity
|| r == null) {
// skip logging in this case
return;
@@ -1085,9 +1081,10 @@ class ActivityStarter {
|| !heavy.mName.equals(aInfo.processName))) {
int appCallingUid = callingUid;
if (caller != null) {
- ProcessRecord callerApp = mService.mAm.getRecordForAppLocked(caller);
+ WindowProcessController callerApp =
+ mService.getProcessController(caller);
if (callerApp != null) {
- appCallingUid = callerApp.info.uid;
+ appCallingUid = callerApp.mInfo.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
@@ -1127,7 +1124,7 @@ class ActivityStarter {
callingUid, realCallingUid, mRequest.filterCallingUid));
aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
- aInfo = mService.mAm.getActivityInfoForUser(aInfo, userId);
+ aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
}
}
}
@@ -1477,7 +1474,7 @@ class ActivityStarter {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
- result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
+ result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
@@ -1493,8 +1490,9 @@ class ActivityStarter {
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
- mService.mAm.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
- UserHandle.getAppId(mStartActivity.appInfo.uid), UserHandle.getAppId(mCallingUid));
+ mService.getPackageManagerInternalLocked().grantEphemeralAccess(
+ mStartActivity.userId, mIntent, UserHandle.getAppId(mStartActivity.appInfo.uid),
+ UserHandle.getAppId(mCallingUid));
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
mStartActivity.getTask().taskId);
@@ -1606,13 +1604,18 @@ class ActivityStarter {
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
- mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
-
mLaunchParams.reset();
mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
options, mLaunchParams);
+ if (mLaunchParams.hasPreferredDisplay()) {
+ mPreferredDisplayId = mLaunchParams.mPreferredDisplayId;
+ } else {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+ ensureValidPreferredDisplayId(r);
+
mLaunchMode = r.launchMode;
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
@@ -1704,6 +1707,24 @@ class ActivityStarter {
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
}
+ /**
+ * Ensure preferred display ID matches the starting activity.
+ */
+ private void ensureValidPreferredDisplayId(ActivityRecord startingActivity) {
+ // Check if the Activity is a VR activity. If so, the activity should be launched in
+ // main display.
+ if (startingActivity != null && startingActivity.requestedVrComponent != null) {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+
+ // Get the virtual display ID from ActivityStackManagerService. If that's set we should
+ // always use that.
+ final int displayId = mService.mVr2dDisplayId;
+ if (displayId != INVALID_DISPLAY) {
+ mPreferredDisplayId = displayId;
+ }
+ }
+
private void sendNewTaskResultRequestIfNeeded() {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
@@ -1883,44 +1904,6 @@ class ActivityStarter {
}
/**
- * Returns the ID of the display to use for a new activity. If the device is in VR mode,
- * then return the Vr mode's virtual display ID. If not, if the activity was started with
- * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID
- * set, use that to launch the activity.
- */
- private int getPreferedDisplayId(
- ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) {
- // Check if the Activity is a VR activity. If so, the activity should be launched in
- // main display.
- if (startingActivity != null && startingActivity.requestedVrComponent != null) {
- return DEFAULT_DISPLAY;
- }
-
- // Get the virtual display id from ActivityManagerService.
- int displayId = mService.mVr2dDisplayId;
- if (displayId != INVALID_DISPLAY) {
- if (DEBUG_STACK) {
- Slog.d(TAG, "getSourceDisplayId :" + displayId);
- }
- return displayId;
- }
-
- // If the caller requested a display, prefer that display.
- final int launchDisplayId =
- (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY;
- if (launchDisplayId != INVALID_DISPLAY) {
- return launchDisplayId;
- }
-
- displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY;
- // If the activity has a displayId set explicitly, launch it on the same displayId.
- if (displayId != INVALID_DISPLAY) {
- return displayId;
- }
- return DEFAULT_DISPLAY;
- }
-
- /**
* Figure out which task and activity to bring to front when we have found an existing matching
* activity record in history. May also clear the task if needed.
* @param intentActivity Existing matching activity.
@@ -2125,8 +2108,7 @@ class ActivityStarter {
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
}
- private int setTaskFromReuseOrCreateNewTask(
- TaskRecord taskToAffiliate, ActivityStack topStack) {
+ private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
// Do no move the target stack to front yet, as we might bail if
@@ -2431,17 +2413,6 @@ class ActivityStarter {
}
}
if (stack == null) {
- // We first try to put the task in the first dynamic stack on home display.
- final ActivityDisplay display = mSupervisor.getDefaultDisplay();
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- stack = display.getChildAt(stackNdx);
- if (!stack.isOnHomeDisplay()) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Setting focused stack=" + stack);
- return stack;
- }
- }
- // If there is no suitable dynamic stack then we figure out which static stack to use.
stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java
new file mode 100644
index 000000000000..cf727380ae6b
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java
@@ -0,0 +1,91 @@
+/*
+ * 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.am;
+
+/**
+ * Common class for the various debug {@link android.util.Log} output configuration relating to
+ * activities.
+ */
+public class ActivityTaskManagerDebugConfig {
+ // All output logs relating to acitvities use the {@link #TAG_ATM} string for tagging their log
+ // output. This makes it easy to identify the origin of the log message when sifting
+ // through a large amount of log output from multiple sources. However, it also makes trying
+ // to figure-out the origin of a log message while debugging the activity manager a little
+ // painful. By setting this constant to true, log messages from the activity manager package
+ // will be tagged with their class names instead fot the generic tag.
+ static final boolean TAG_WITH_CLASS_NAME = false;
+
+ // While debugging it is sometimes useful to have the category name of the log appended to the
+ // base log tag to make sifting through logs with the same base tag easier. By setting this
+ // constant to true, the category name of the log point will be appended to the log tag.
+ private static final boolean APPEND_CATEGORY_NAME = false;
+
+ // Default log tag for the activities.
+ static final String TAG_ATM = "ActivityTaskManager";
+
+ // Enable all debug log categories.
+ static final boolean DEBUG_ALL = false;
+
+ // Enable all debug log categories for activities.
+ private static final boolean DEBUG_ALL_ACTIVITIES = DEBUG_ALL || false;
+
+ static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_CONFIGURATION = DEBUG_ALL || false;
+ static final boolean DEBUG_CONTAINERS = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_FOCUS = false;
+ static final boolean DEBUG_IMMERSIVE = DEBUG_ALL || false;
+ static final boolean DEBUG_LOCKTASK = DEBUG_ALL || false;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+ static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
+ static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
+ static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_STACK = DEBUG_ALL || false;
+ static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
+ static final boolean DEBUG_TASKS = DEBUG_ALL || false;
+ static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
+ static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
+ static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_IDLE = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_RELEASE = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
+ static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
+ static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
+ static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;
+ static final boolean DEBUG_METRICS = DEBUG_ALL || false;
+
+ static final String POSTFIX_APP = APPEND_CATEGORY_NAME ? "_App" : "";
+ static final String POSTFIX_IDLE = APPEND_CATEGORY_NAME ? "_Idle" : "";
+ static final String POSTFIX_RELEASE = APPEND_CATEGORY_NAME ? "_Release" : "";
+ static final String POSTFIX_USER_LEAVING = APPEND_CATEGORY_NAME ? "_UserLeaving" : "";
+ static final String POSTFIX_ADD_REMOVE = APPEND_CATEGORY_NAME ? "_AddRemove" : "";
+ static final String POSTFIX_CONFIGURATION = APPEND_CATEGORY_NAME ? "_Configuration" : "";
+ static final String POSTFIX_CONTAINERS = APPEND_CATEGORY_NAME ? "_Containers" : "";
+ static final String POSTFIX_FOCUS = APPEND_CATEGORY_NAME ? "_Focus" : "";
+ static final String POSTFIX_IMMERSIVE = APPEND_CATEGORY_NAME ? "_Immersive" : "";
+ static final String POSTFIX_LOCKTASK = APPEND_CATEGORY_NAME ? "_LockTask" : "";
+ static final String POSTFIX_PAUSE = APPEND_CATEGORY_NAME ? "_Pause" : "";
+ static final String POSTFIX_RECENTS = APPEND_CATEGORY_NAME ? "_Recents" : "";
+ static final String POSTFIX_SAVED_STATE = APPEND_CATEGORY_NAME ? "_SavedState" : "";
+ static final String POSTFIX_STACK = APPEND_CATEGORY_NAME ? "_Stack" : "";
+ static final String POSTFIX_STATES = APPEND_CATEGORY_NAME ? "_States" : "";
+ static final String POSTFIX_SWITCH = APPEND_CATEGORY_NAME ? "_Switch" : "";
+ static final String POSTFIX_TASKS = APPEND_CATEGORY_NAME ? "_Tasks" : "";
+ static final String POSTFIX_TRANSITION = APPEND_CATEGORY_NAME ? "_Transition" : "";
+ static final String POSTFIX_VISIBILITY = APPEND_CATEGORY_NAME ? "_Visibility" : "";
+ static final String POSTFIX_RESULTS = APPEND_CATEGORY_NAME ? "_Results" : "";
+}
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 8e3eeae5d569..6398680b7122 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -40,6 +40,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ApplicationInfo.FLAG_FACTORY_TEST;
+import static android.content.pm.ConfigurationInfo.GL_ES_VERSION_UNDEFINED;
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_PC;
@@ -67,29 +68,26 @@ import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-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.ANIMATE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_IMMERSIVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
-import static com.android.server.am.ActivityManagerService.SEND_LOCALE_TO_MOUNT_DAEMON_MSG;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
-import static com.android.server.am.ActivityManagerService.UPDATE_CONFIGURATION_MSG;
import static com.android.server.am.ActivityManagerService.dumpStackTraces;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
@@ -100,7 +98,7 @@ import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.am.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
import static com.android.server.am.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
@@ -141,8 +139,7 @@ import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
-import android.app.servertransaction.ConfigurationChangeItem;
-import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -180,6 +177,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -190,6 +188,8 @@ import android.os.UpdateLock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
+import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
@@ -231,6 +231,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.Watchdog;
+import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.UserManagerService;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.vr.VrManagerInternal;
@@ -255,7 +256,7 @@ import java.util.Locale;
* {@hide}
*/
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
@@ -269,12 +270,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// How long we wait until we timeout on key dispatching during instrumentation.
private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ /** Used to indicate that an app transition should be animated. */
+ static final boolean ANIMATE = true;
+
+ /** Hardware-reported OpenGLES version. */
+ final int GL_ES_VERSION;
+
Context mContext;
/**
* This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
* change at runtime. Use mContext for non-UI purposes.
*/
final Context mUiContext;
+ final ActivityThread mSystemThread;
H mH;
UiHandler mUiHandler;
ActivityManagerService mAm;
@@ -282,7 +290,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
UriGrantsManagerInternal mUgmInternal;
private PackageManagerInternal mPmInternal;
private ActivityTaskManagerInternal mInternal;
+ PowerManagerInternal mPowerManagerInternal;
+ private UsageStatsManagerInternal mUsageStatsInternal;
+
PendingIntentController mPendingIntentController;
+ IntentFirewall mIntentFirewall;
+
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
@@ -537,8 +550,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ActivityTaskManagerService(Context context) {
mContext = context;
mFactoryTest = FactoryTest.getMode();
- mUiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+ mSystemThread = ActivityThread.currentActivityThread();
+ mUiContext = mSystemThread.getSystemUiContext();
mLifecycleManager = new ClientLifecycleManager();
+ GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
}
void onSystemReady() {
@@ -552,6 +567,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
void onInitPowerManagement() {
mStackSupervisor.initPowerManagement();
final PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mVoiceWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*voice*");
mVoiceWakeLock.setReferenceCounted(false);
}
@@ -638,15 +654,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
// TODO: Will be converted to WM lock once transition is complete.
- void setActivityManagerService(ActivityManagerService am) {
+ void setActivityManagerService(ActivityManagerService am, Looper looper,
+ IntentFirewall intentFirewall, PendingIntentController intentController) {
mAm = am;
mGlobalLock = mAm;
- mH = new H(mAm.mHandlerThread.getLooper());
+ mH = new H(looper);
mUiHandler = new UiHandler();
+ mIntentFirewall = intentFirewall;
final File systemDir = SystemServiceManager.ensureSystemDir();
mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir);
mCompatModePackages = new CompatModePackages(this, systemDir, mH);
- mPendingIntentController = mAm.mPendingIntentController;
+ mPendingIntentController = intentController;
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
@@ -685,6 +703,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mLockTaskController.setWindowManager(wm);
}
+ void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
+ mUsageStatsInternal = usageStatsManager;
+ }
+
UserManagerService getUserManager() {
if (mUserManager == null) {
IBinder b = ServiceManager.getService(Context.USER_SERVICE);
@@ -764,7 +786,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
&& globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
}
- config.reqGlEsVersion = mAm.GL_ES_VERSION;
+ config.reqGlEsVersion = GL_ES_VERSION;
}
return config;
}
@@ -1707,7 +1729,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
final ActivityRecord r = stack.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedStack")) {
+ if (r != null && r.moveFocusableActivityToTop("setFocusedStack")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -1728,7 +1750,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
final ActivityRecord r = task.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedTask")) {
+ if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -2762,8 +2784,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
- WindowProcessController app =
- mAm.getRecordForAppLocked(appInt).getWindowProcessController();
+ final WindowProcessController app = getProcessController(appInt);
mStackSupervisor.releaseSomeActivitiesLocked(app, "low-mem");
} finally {
Binder.restoreCallingIdentity(origId);
@@ -2784,7 +2805,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
long ident = Binder.clearCallingIdentity();
if (mKeyguardShown != keyguardShowing) {
mKeyguardShown = keyguardShowing;
- reportCurKeyguardUsageEventLocked(keyguardShowing);
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::reportCurKeyguardUsageEvent, mAmInternal,
+ keyguardShowing);
+ mH.sendMessage(msg);
}
try {
mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
@@ -2921,12 +2945,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mTaskChangeNotificationController.unregisterTaskStackListener(listener);
}
- private void reportCurKeyguardUsageEventLocked(boolean keyguardShowing) {
- mAm.reportGlobalUsageEventLocked(keyguardShowing
- ? UsageEvents.Event.KEYGUARD_SHOWN
- : UsageEvents.Event.KEYGUARD_HIDDEN);
- }
-
@Override
public boolean requestAssistContextExtras(int requestType, IAssistDataReceiver receiver,
Bundle receiverExtras, IBinder activityToken, boolean focused, boolean newSessionId) {
@@ -3893,8 +3911,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
if (mWindowManager != null) {
- // Update OOM levels based on display size.
- mAm.mProcessList.applyDisplaySize(mWindowManager);
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal, displayId);
+ mH.sendMessage(msg);
}
final long origId = Binder.clearCallingIdentity();
@@ -3922,8 +3941,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
if (mWindowManager != null) {
- // Update OOM levels based on display size.
- mAm.mProcessList.applyDisplaySize(mWindowManager);
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal,
+ DEFAULT_DISPLAY);
+ mH.sendMessage(msg);
}
final long origId = Binder.clearCallingIdentity();
@@ -4130,11 +4151,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void setVrThread(int tid) {
enforceSystemHasVrFeature();
synchronized (mGlobalLock) {
- synchronized (mAm.mPidsSelfLocked) {
- final int pid = Binder.getCallingPid();
- final ProcessRecord proc = mAm.mPidsSelfLocked.get(pid);
- mVrController.setVrThreadLocked(tid, pid, proc.getWindowProcessController());
- }
+ final int pid = Binder.getCallingPid();
+ final WindowProcessController wpc = mPidMap.get(pid);
+ mVrController.setVrThreadLocked(tid, pid, wpc);
}
}
@@ -4151,11 +4170,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
enforceSystemHasVrFeature();
synchronized (mGlobalLock) {
- synchronized (mAm.mPidsSelfLocked) {
- final int pid = Binder.getCallingPid();
- final ProcessRecord proc = mAm.mPidsSelfLocked.get(pid);
- mVrController.setPersistentVrThreadLocked(tid, pid, proc);
- }
+ final int pid = Binder.getCallingPid();
+ final WindowProcessController proc = mPidMap.get(pid);
+ mVrController.setPersistentVrThreadLocked(tid, pid, proc);
}
}
@@ -4487,8 +4504,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
- mAm.mHandler.sendMessage(mAm.mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
- locales.get(bestLocaleIndex)));
+
+ final Message m = PooledLambda.obtainMessage(
+ ActivityTaskManagerService::sendLocaleToMountDaemonMsg, this,
+ locales.get(bestLocaleIndex));
+ mH.sendMessage(m);
}
mTempConfig.seq = increaseConfigurationSeqLocked();
@@ -4498,8 +4518,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempConfig);
// TODO(multi-display): Update UsageEvents#Event to include displayId.
- mAm.mUsageStatsService.reportConfigurationChange(
- mTempConfig, mAmInternal.getCurrentUserId());
+ mUsageStatsInternal.reportConfigurationChange(mTempConfig, mAmInternal.getCurrentUserId());
// TODO: If our config changes, should we auto dismiss any currently showing dialogs?
updateShouldShowDialogsLocked(mTempConfig);
@@ -4513,31 +4532,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// to retrieve resource values after we return will be sure to get the new ones. This is
// especially important during boot, where the first config change needs to guarantee all
// resources have that config before following boot code is executed.
- mAm.mSystemThread.applyConfigurationToResources(mTempConfig);
+ mSystemThread.applyConfigurationToResources(mTempConfig);
// We need another copy of global config because we're scheduling some calls instead of
// running them in place. We need to be sure that object we send will be handled unchanged.
final Configuration configCopy = new Configuration(mTempConfig);
if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
- Message msg = mAm.mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
- msg.obj = configCopy;
- msg.arg1 = userId;
- mAm.mHandler.sendMessage(msg);
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityTaskManagerService::sendPutConfigurationForUserMsg,
+ this, userId, configCopy);
+ mH.sendMessage(msg);
}
- // TODO: Consider using mPidMap to update configurations for processes.
- for (int i = mAm.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord app = mAm.mLruProcesses.get(i);
- try {
- if (app.thread != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.processName + " new config " + configCopy);
- getLifecycleManager().scheduleTransaction(app.thread,
- ConfigurationChangeItem.obtain(configCopy));
- }
- } catch (Exception e) {
- Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ for (int i = mPidMap.size() - 1; i >= 0; i--) {
+ WindowProcessController app = mPidMap.get(mPidMap.keyAt(i));
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG_CONFIGURATION, "Update process config of "
+ + app.mName + " to new config " + configCopy);
}
+ app.onConfigurationChanged(configCopy);
}
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -4666,6 +4679,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mWindowManager.setEventDispatching(booted && !mShuttingDown);
}
+ private void sendPutConfigurationForUserMsg(int userId, Configuration config) {
+ final ContentResolver resolver = mContext.getContentResolver();
+ Settings.System.putConfigurationForUser(resolver, config, userId);
+ }
+
+ private void sendLocaleToMountDaemonMsg(Locale l) {
+ try {
+ IBinder service = ServiceManager.getService("mount");
+ IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
+ Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
+ storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error storing locale for decryption UI", e);
+ }
+ }
+
+ boolean isActivityStartsLoggingEnabled() {
+ return mAmInternal.isActivityStartsLoggingEnabled();
+ }
+
void enableScreenAfterBoot(boolean booted) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
@@ -5273,6 +5306,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mProcessNames.get(processName, uid);
}
+ WindowProcessController getProcessController(IApplicationThread thread) {
+ if (thread == null) {
+ return null;
+ }
+
+ final IBinder threadBinder = thread.asBinder();
+ final ArrayMap<String, SparseArray<WindowProcessController>> pmap = mProcessNames.getMap();
+ for (int i = pmap.size()-1; i >= 0; i--) {
+ final SparseArray<WindowProcessController> procs = pmap.valueAt(i);
+ for (int j = procs.size() - 1; j >= 0; j--) {
+ final WindowProcessController proc = procs.valueAt(j);
+ if (proc.hasThread() && proc.getThread().asBinder() == threadBinder) {
+ return proc;
+ }
+ }
+ }
+
+ return null;
+ }
+
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
if (true || Build.IS_USER) {
return;
@@ -5334,6 +5387,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final class H extends Handler {
static final int REPORT_TIME_TRACKER_MSG = 1;
+ static final int FIRST_ACTIVITY_STACK_MSG = 100;
+ static final int FIRST_SUPERVISOR_STACK_MSG = 200;
public H(Looper looper) {
super(looper, null, true);
@@ -5554,7 +5609,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new IllegalArgumentException(
"setFocusedActivity: No activity record matching token=" + token);
}
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedActivity")) {
+ if (r.moveFocusableActivityToTop("setFocusedActivity")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -5978,7 +6033,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mUiHandler.post(() -> {
Dialog d = new FactoryErrorDialog(mUiContext, errorMsg);
d.show();
- mAm.ensureBootCompleted();
+ mAmInternal.ensureBootCompleted();
});
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 6a9c8877ce5b..a05fbc695370 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -684,7 +684,7 @@ class AppErrors {
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
final boolean procIsBoundForeground =
- (app.curProcState == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ (app.getCurProcState() == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
Long crashTime;
Long crashTimePersistent;
@@ -878,7 +878,7 @@ class AppErrors {
// several places in the system server.
return app.isInterestingToUserLocked() ||
(app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
- (app.hasTopUi || app.hasOverlayUi);
+ (app.hasTopUi() || app.hasOverlayUi());
}
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 536f3a93a3f1..3c4ab006a4b6 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -16,8 +16,11 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import java.io.File;
import java.io.FileInputStream;
@@ -48,7 +51,7 @@ import android.util.Slog;
import android.util.Xml;
public final class CompatModePackages {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_ATM;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private final ActivityTaskManagerService mService;
@@ -61,7 +64,7 @@ public final class CompatModePackages {
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
- private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG;
+ private static final int MSG_WRITE = 300;
private final CompatHandler mHandler;
@@ -321,16 +324,16 @@ public final class CompatModePackages {
ActivityRecord starting = stack.restartPackage(packageName);
// Tell all processes that loaded this package about the change.
- for (int i = mService.mAm.mLruProcesses.size() - 1; i >= 0; i--) {
- final ProcessRecord app = mService.mAm.mLruProcesses.get(i);
- if (!app.pkgList.containsKey(packageName)) {
+ for (int i = mService.mPidMap.size() - 1; i >= 0; i--) {
+ final WindowProcessController app = mService.mPidMap.valueAt(i);
+ if (!app.mPkgList.contains(packageName)) {
continue;
}
try {
- if (app.thread != null) {
+ if (app.hasThread()) {
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
- + app.processName + " new compat " + ci);
- app.thread.updatePackageCompatibilityInfo(packageName, ci);
+ + app.mName + " new compat " + ci);
+ app.getThread().updatePackageCompatibilityInfo(packageName, ci);
}
} catch (Exception e) {
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 160c753d9540..2ca134465cd6 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -55,6 +55,11 @@ final class CoreSettingsObserver extends ContentObserver {
// add other system settings here...
sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
index e5add58f287a..b39873fe4335 100644
--- a/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
+++ b/services/core/java/com/android/server/am/DeprecatedTargetSdkVersionDialog.java
@@ -16,8 +16,8 @@
package com.android.server.am;
-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.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.AlertDialog;
import android.content.Context;
@@ -34,7 +34,7 @@ import com.android.internal.R;
import com.android.server.utils.AppInstallerUtil;
public class DeprecatedTargetSdkVersionDialog {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "DeprecatedTargetSdkVersionDialog" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "DeprecatedTargetSdkVersionDialog" : TAG_ATM;
private final AlertDialog mDialog;
private final String mPackageName;
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index cfe282917f3b..28b2a42522eb 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -30,9 +30,9 @@ import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
-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.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
@@ -60,7 +60,7 @@ import java.io.PrintWriter;
*/
class KeyguardController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_ATM;
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 6415c3ee7f72..218d9080c2c0 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -16,6 +16,13 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
import android.annotation.IntDef;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo.WindowLayout;
@@ -26,13 +33,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
/**
* {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
* registered {@link LaunchParamsModifier}s.
@@ -58,11 +58,7 @@ class LaunchParamsController {
*/
void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
// {@link TaskLaunchParamsModifier} handles window layout preferences.
- registerModifier(new TaskLaunchParamsModifier());
-
- // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
- // registered last (applied first) out of the defaults.
- registerModifier(new ActivityLaunchParamsModifier(supervisor));
+ registerModifier(new TaskLaunchParamsModifier(supervisor));
}
/**
@@ -226,27 +222,41 @@ class LaunchParamsController {
@IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
@interface Result {}
- // Returned when the modifier does not want to influence the bounds calculation
+ /** Returned when the modifier does not want to influence the bounds calculation */
int RESULT_SKIP = 0;
- // Returned when the modifier has changed the bounds and would like its results to be the
- // final bounds applied.
+ /**
+ * Returned when the modifier has changed the bounds and would like its results to be the
+ * final bounds applied.
+ */
int RESULT_DONE = 1;
- // Returned when the modifier has changed the bounds but is okay with other modifiers
- // influencing the bounds.
+ /**
+ * Returned when the modifier has changed the bounds but is okay with other modifiers
+ * influencing the bounds.
+ */
int RESULT_CONTINUE = 2;
/**
- * Called when asked to calculate {@link LaunchParams}.
- * @param task The {@link TaskRecord} currently being positioned.
- * @param layout The specified {@link WindowLayout}.
- * @param activity The {@link ActivityRecord} currently being positioned.
- * @param source The {@link ActivityRecord} activity was started from.
- * @param options The {@link ActivityOptions} specified for the activity.
- * @param currentParams The current {@link LaunchParams}. This can differ from the initial
- * params as it represents the modified params up to this point.
- * @param outParams The resulting {@link LaunchParams} after all calculations.
- * @return A {@link Result} representing the result of the
- * {@link LaunchParams} calculation.
+ * Returns the launch params that the provided activity launch params should be overridden
+ * to. {@link LaunchParamsModifier} can use this for various purposes, including: 1)
+ * Providing default bounds if the launch bounds have not been provided. 2) Repositioning
+ * the task so it doesn't get placed over an existing task. 3) Resizing the task so that its
+ * dimensions match the activity's requested orientation.
+ *
+ * @param task Can be: 1) the target task in which the source activity wants to
+ * launch the target activity; 2) a newly created task that Android
+ * gives a chance to override its launching bounds; 3) {@code null} if
+ * this is called to override an activity's launching bounds.
+ * @param layout Desired layout when activity is first launched.
+ * @param activity Activity that is being started. This can be {@code null} on
+ * re-parenting an activity to a new task (e.g. for
+ * Picture-In-Picture). Tasks being created because an activity was
+ * launched should have this be non-null.
+ * @param source the Activity that launched a new task. Could be {@code null}.
+ * @param options {@link ActivityOptions} used to start the activity with.
+ * @param currentParams launching params after the process of last {@link
+ * LaunchParamsModifier}.
+ * @param outParams the result params to be set.
+ * @return see {@link LaunchParamsModifier.Result}
*/
@Result
int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 643c922ad2ca..5b31d5fc593f 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -28,10 +28,10 @@ import static android.os.UserHandle.USER_CURRENT;
import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-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.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -84,7 +84,7 @@ import java.util.Arrays;
* @see Activity#stopLockTask()
*/
public class LockTaskController {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "LockTaskController" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "LockTaskController" : TAG_ATM;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
@VisibleForTesting
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index a8e1ccca8b9d..98f3f95ebb87 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -16,7 +16,7 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3ac7885eba37..9e7ce3204444 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -162,9 +162,11 @@ public final class ProcessList {
// LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
// LMK_PROCPRIO <pid> <uid> <prio>
// LMK_PROCREMOVE <pid>
+ // LMK_PROCPURGE
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
+ static final byte LMK_PROCPURGE = 3;
// These are the various interesting memory levels that we will give to
// the OOM killer. Note that the OOM killer only supports 6 slots, so we
@@ -813,31 +815,46 @@ public final class ProcessList {
return true;
}
+ // Never call directly, use writeLmkd() instead
+ private static boolean writeLmkdCommand(ByteBuffer buf) {
+ try {
+ sLmkdOutputStream.write(buf.array(), 0, buf.position());
+ } catch (IOException ex) {
+ Slog.w(TAG, "Error writing to lowmemorykiller socket");
+
+ try {
+ sLmkdSocket.close();
+ } catch (IOException ex2) {
+ }
+
+ sLmkdSocket = null;
+ return false;
+ }
+ return true;
+ }
+
private static void writeLmkd(ByteBuffer buf) {
for (int i = 0; i < 3; i++) {
if (sLmkdSocket == null) {
- if (openLmkdSocket() == false) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException ie) {
- }
- continue;
+ if (openLmkdSocket() == false) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
}
- }
-
- try {
- sLmkdOutputStream.write(buf.array(), 0, buf.position());
- return;
- } catch (IOException ex) {
- Slog.w(TAG, "Error writing to lowmemorykiller socket");
-
- try {
- sLmkdSocket.close();
- } catch (IOException ex2) {
+ continue;
}
- sLmkdSocket = null;
+ // Purge any previously registered pids
+ ByteBuffer purge_buf = ByteBuffer.allocate(4);
+ purge_buf.putInt(LMK_PROCPURGE);
+ if (writeLmkdCommand(purge_buf) == false) {
+ // Write failed, skip the rest and retry
+ continue;
+ }
+ }
+ if (writeLmkdCommand(buf)) {
+ return;
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 667d3faefc9f..3128333def6f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -136,7 +136,7 @@ final class ProcessRecord implements WindowProcessListener {
private int mCurSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
int trimMemoryLevel; // Last selected memory trimming level
- int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
+ private int mCurProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
private int mRepProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
@@ -146,19 +146,19 @@ final class ProcessRecord implements WindowProcessListener {
boolean serviceb; // Process currently is on the service B list
boolean serviceHighRam; // We are forcing to service B list due to its RAM use
boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
- boolean hasClientActivities; // Are there any client services with activities?
+ private boolean mHasClientActivities; // Are there any client services with activities?
boolean hasStartedServices; // Are there any started services running in this process?
private boolean mHasForegroundServices; // Running any services that are foreground?
- boolean foregroundActivities; // Running any activities that are foreground?
+ private boolean mHasForegroundActivities; // Running any activities that are foreground?
boolean repForegroundActivities; // Last reported foreground activities.
boolean systemNoUi; // This is a system process, but not currently showing UI.
boolean hasShownUi; // Has UI been shown in this process since it was started?
- boolean hasTopUi; // Is this process currently showing a non-activity UI that the user
+ private boolean mHasTopUi; // Is this process currently showing a non-activity UI that the user
// is interacting with? E.g. The status bar when it is expanded, but
// not when it is minimized. When true the
// process will be set to use the ProcessList#SCHED_GROUP_TOP_APP
// scheduling group to boost performance.
- boolean hasOverlayUi; // Is the process currently showing a non-activity UI that
+ private boolean mHasOverlayUi; // Is the process currently showing a non-activity UI that
// overlays on-top of activity UIs on screen. E.g. display a window
// of type
// android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY
@@ -171,7 +171,7 @@ final class ProcessRecord implements WindowProcessListener {
// performance, as well as oom adj score will be set to
// ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance
// of the process getting killed.
- boolean pendingUiClean; // Want to clean up resources from showing UI?
+ private boolean mPendingUiClean; // Want to clean up resources from showing UI?
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY
boolean bad; // True if disabled in the bad process list
@@ -180,8 +180,8 @@ final class ProcessRecord implements WindowProcessListener {
boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
boolean reportedInteraction;// Whether we have told usage stats about it being an interaction
boolean unlocked; // True when proc was started in user unlocked state
- long interactionEventTime; // The time we sent the last interaction event
- long fgInteractionTime; // When we became foreground for interaction purposes
+ private long mInteractionEventTime; // The time we sent the last interaction event
+ private long mFgInteractionTime; // When we became foreground for interaction purposes
String waitingToKill; // Process is waiting to be killed when in the bg, and reason
Object forcingToImportant; // Token that is forcing this process to be important
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
@@ -194,7 +194,7 @@ final class ProcessRecord implements WindowProcessListener {
// process.
private boolean mUsingWrapper; // Set to true when process was launched with a wrapper attached
final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
- long whenUnimportant; // When (uptime) the process last became unimportant
+ private long mWhenUnimportant; // When (uptime) the process last became unimportant
long lastCpuTime; // How long proc has run CPU at last check
long curCpuTime; // How long proc has run CPU most recently
long lastRequestedGc; // When we last asked the app to do a gc
@@ -370,38 +370,38 @@ final class ProcessRecord implements WindowProcessListener {
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
+ pw.print(prefix); pw.print("curProcState="); pw.print(getCurProcState());
pw.print(" mRepProcState="); pw.print(mRepProcState);
pw.print(" pssProcState="); pw.print(pssProcState);
pw.print(" setProcState="); pw.print(setProcState);
pw.print(" lastStateTime=");
TimeUtils.formatDuration(lastStateTime, nowUptime, pw);
pw.println();
- if (hasShownUi || pendingUiClean || hasAboveClient || treatLikeActivity) {
+ if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
- pw.print(" pendingUiClean="); pw.print(pendingUiClean);
+ pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
pw.print(" hasAboveClient="); pw.print(hasAboveClient);
pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
- if (hasTopUi || hasOverlayUi || runningRemoteAnimation) {
- pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi);
- pw.print(" hasOverlayUi="); pw.print(hasOverlayUi);
+ if (hasTopUi() || hasOverlayUi() || runningRemoteAnimation) {
+ pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi());
+ pw.print(" hasOverlayUi="); pw.print(hasOverlayUi());
pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation);
}
if (mHasForegroundServices || forcingToImportant != null) {
pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
pw.print(" forcingToImportant="); pw.println(forcingToImportant);
}
- if (reportedInteraction || fgInteractionTime != 0) {
+ if (reportedInteraction || mFgInteractionTime != 0) {
pw.print(prefix); pw.print("reportedInteraction=");
pw.print(reportedInteraction);
- if (interactionEventTime != 0) {
+ if (mInteractionEventTime != 0) {
pw.print(" time=");
- TimeUtils.formatDuration(interactionEventTime, SystemClock.elapsedRealtime(), pw);
+ TimeUtils.formatDuration(mInteractionEventTime, SystemClock.elapsedRealtime(), pw);
}
- if (fgInteractionTime != 0) {
+ if (mFgInteractionTime != 0) {
pw.print(" fgInteractionTime=");
- TimeUtils.formatDuration(fgInteractionTime, SystemClock.elapsedRealtime(), pw);
+ TimeUtils.formatDuration(mFgInteractionTime, SystemClock.elapsedRealtime(), pw);
}
pw.println();
}
@@ -409,9 +409,9 @@ final class ProcessRecord implements WindowProcessListener {
pw.print(prefix); pw.print("persistent="); pw.print(mPersistent);
pw.print(" removed="); pw.println(removed);
}
- if (hasClientActivities || foregroundActivities || repForegroundActivities) {
- pw.print(prefix); pw.print("hasClientActivities="); pw.print(hasClientActivities);
- pw.print(" foregroundActivities="); pw.print(foregroundActivities);
+ if (mHasClientActivities || mHasForegroundActivities || repForegroundActivities) {
+ pw.print(prefix); pw.print("hasClientActivities="); pw.print(mHasClientActivities);
+ pw.print(" foregroundActivities="); pw.print(mHasForegroundActivities);
pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")");
}
if (lastProviderTime > 0) {
@@ -438,7 +438,7 @@ final class ProcessRecord implements WindowProcessListener {
TimeUtils.formatDuration(curCpuTime - lastCpuTime, pw);
}
pw.print(" whenUnimportant=");
- TimeUtils.formatDuration(whenUnimportant - nowUptime, pw);
+ TimeUtils.formatDuration(mWhenUnimportant - nowUptime, pw);
pw.println();
}
pw.print(prefix); pw.print("lastRequestedGc=");
@@ -857,7 +857,8 @@ final class ProcessRecord implements WindowProcessListener {
public void forceProcessStateUpTo(int newState) {
if (mRepProcState > newState) {
- curProcState = mRepProcState = newState;
+ mRepProcState = newState;
+ setCurProcState(newState);
for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
StatsLog.write(StatsLog.PROCESS_STATE_CHANGED,
uid, processName, pkgList.keyAt(ipkg),
@@ -931,6 +932,15 @@ final class ProcessRecord implements WindowProcessListener {
return mCurSchedGroup;
}
+ void setCurProcState(int curProcState) {
+ mCurProcState = curProcState;
+ mWindowProcessController.setCurrentProcState(mCurProcState);
+ }
+
+ int getCurProcState() {
+ return mCurProcState;
+ }
+
void setReportedProcState(int repProcState) {
mRepProcState = repProcState;
for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
@@ -991,6 +1001,69 @@ final class ProcessRecord implements WindowProcessListener {
return mHasForegroundServices;
}
+ void setHasForegroundActivities(boolean hasForegroundActivities) {
+ mHasForegroundActivities = hasForegroundActivities;
+ mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
+ }
+
+ boolean hasForegroundActivities() {
+ return mHasForegroundActivities;
+ }
+
+ void setHasClientActivities(boolean hasClientActivities) {
+ mHasClientActivities = hasClientActivities;
+ mWindowProcessController.setHasClientActivities(hasClientActivities);
+ }
+
+ boolean hasClientActivities() {
+ return mHasClientActivities;
+ }
+
+ void setHasTopUi(boolean hasTopUi) {
+ mHasTopUi = hasTopUi;
+ mWindowProcessController.setHasTopUi(hasTopUi);
+ }
+
+ boolean hasTopUi() {
+ return mHasTopUi;
+ }
+
+ void setHasOverlayUi(boolean hasOverlayUi) {
+ mHasOverlayUi = hasOverlayUi;
+ mWindowProcessController.setHasOverlayUi(hasOverlayUi);
+ }
+
+ boolean hasOverlayUi() {
+ return mHasOverlayUi;
+ }
+
+ void setInteractionEventTime(long interactionEventTime) {
+ mInteractionEventTime = interactionEventTime;
+ mWindowProcessController.setInteractionEventTime(interactionEventTime);
+ }
+
+ long getInteractionEventTime() {
+ return mInteractionEventTime;
+ }
+
+ void setFgInteractionTime(long fgInteractionTime) {
+ mFgInteractionTime = fgInteractionTime;
+ mWindowProcessController.setFgInteractionTime(fgInteractionTime);
+ }
+
+ long getFgInteractionTime() {
+ return mFgInteractionTime;
+ }
+
+ void setWhenUnimportant(long whenUnimportant) {
+ mWhenUnimportant = whenUnimportant;
+ mWindowProcessController.setWhenUnimportant(whenUnimportant);
+ }
+
+ long getWhenUnimportant() {
+ return mWhenUnimportant;
+ }
+
void setDebugging(boolean debugging) {
mDebugging = debugging;
mWindowProcessController.setDebugging(debugging);
@@ -1039,14 +1112,19 @@ final class ProcessRecord implements WindowProcessListener {
@Override
public void setPendingUiClean(boolean pendingUiClean) {
synchronized (mService) {
- this.pendingUiClean = true;
+ mPendingUiClean = pendingUiClean;
+ mWindowProcessController.setPendingUiClean(pendingUiClean);
}
}
+ boolean hasPendingUiClean() {
+ return mPendingUiClean;
+ }
+
@Override
public void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
synchronized (mService) {
- pendingUiClean = true;
+ setPendingUiClean(true);
forceProcessStateUpTo(newState);
}
}
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index dd13e9868b1d..57f939f4438b 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -33,15 +33,15 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-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.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -103,7 +103,7 @@ import java.util.concurrent.TimeUnit;
* // 'X' tasks are trimmed.
*/
class RecentTasks {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_ATM;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index fa0cb47ade02..115216592e71 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -21,9 +21,9 @@ import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.INVALID_DISPLAY;
-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.TaskRecord.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -46,7 +46,7 @@ import com.android.internal.annotations.VisibleForTesting;
*/
public class SafeActivityOptions {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_ATM;
private final int mOriginalCallingPid;
private final int mOriginalCallingUid;
diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index 92f1cc34be92..7bd84e23af81 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -16,304 +16,770 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.graphics.Rect;
+import android.os.Build;
import android.util.Slog;
import android.view.Gravity;
-import com.android.internal.annotations.VisibleForTesting;
+
import com.android.server.am.LaunchParamsController.LaunchParams;
import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
import java.util.ArrayList;
+import java.util.List;
/**
- * Determines where a launching task should be positioned and sized on the display.
- *
- * The modifier is fairly simple. For the new task it tries default position based on the gravity
- * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
- * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
- * all possible shifts, it gives up and puts the task in the original position.
- *
- * Note that the only gravities of concern are the corners and the center.
+ * The class that defines the default launch params for tasks.
*/
class TaskLaunchParamsModifier implements LaunchParamsModifier {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_ATM;
+ private static final boolean DEBUG = false;
- // Determines how close window frames/corners have to be to call them colliding.
- private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
+ // A mask for SUPPORTS_SCREEN that indicates the activity supports resize.
+ private static final int SUPPORTS_SCREEN_RESIZEABLE_MASK =
+ ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+ | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
- // Task will receive dimensions based on available dimensions divided by this.
- private static final int WINDOW_SIZE_DENOMINATOR = 2;
+ // Screen size of Nexus 5x
+ private static final int DEFAULT_PORTRAIT_PHONE_WIDTH_DP = 412;
+ private static final int DEFAULT_PORTRAIT_PHONE_HEIGHT_DP = 732;
- // Task will receive margins based on available dimensions divided by this.
- private static final int MARGIN_SIZE_DENOMINATOR = 4;
+ // Allowance of size matching.
+ private static final int EPSILON = 2;
- // If task bounds collide with some other, we will step and try again until we find a good
- // position. The step will be determined by using dimensions and dividing it by this.
+ // Cascade window offset.
+ private static final int CASCADING_OFFSET_DP = 75;
+
+ // Threshold how close window corners have to be to call them colliding.
+ private static final int BOUNDS_CONFLICT_THRESHOLD = 4;
+
+ // Divide display size by this number to get each step to adjust bounds to avoid conflict.
private static final int STEP_DENOMINATOR = 16;
// We always want to step by at least this.
private static final int MINIMAL_STEP = 1;
- // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
- // reaches the end of stack bounds.
- private static final boolean ALLOW_RESTART = true;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Rect mTmpBounds = new Rect();
+ private final int[] mTmpDirections = new int[2];
- private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
- private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
- private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+ private StringBuilder mLogBuilder;
- private final Rect mAvailableRect = new Rect();
- private final Rect mTmpProposal = new Rect();
- private final Rect mTmpOriginal = new Rect();
+ TaskLaunchParamsModifier(ActivityStackSupervisor supervisor) {
+ mSupervisor = supervisor;
+ }
- /**
- * Tries to set task's bound in a way that it won't collide with any other task. By colliding
- * we mean that two tasks have left-top corner very close to each other, so one might get
- * obfuscated by the other one.
- */
@Override
public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options,
LaunchParams currentParams, LaunchParams outParams) {
- // We can only apply positioning if we're in a freeform stack.
- if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
- return RESULT_SKIP;
- }
+ initLogBuilder(task, activity);
+ final int result = calculate(task, layout, activity, source, options, currentParams,
+ outParams);
+ outputLog();
+ return result;
+ }
- final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
+ private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
+ // STEP 1: Determine the display to launch the activity/task.
+ final int displayId = getPreferredLaunchDisplay(options, source, currentParams);
+ outParams.mPreferredDisplayId = displayId;
+ ActivityDisplay display = mSupervisor.getActivityDisplay(displayId);
+ if (DEBUG) {
+ appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
+ + display.getWindowingMode());
+ }
- mAvailableRect.set(task.getParent().getBounds());
+ final ActivityRecord root;
+ if (task != null) {
+ root = (task.getRootActivity() == null ? activity : task.getRootActivity());
+ } else {
+ root = activity;
+ }
+ // STEP 2: Resolve launch windowing mode.
+ // STEP 2.1: Determine if any parameter has specified initial bounds. That might be the
+ // launch bounds from activity options, or size/gravity passed in layout. It also treat the
+ // launch windowing mode in options as a suggestion for future resolution.
+ int launchMode = options != null ? options.getLaunchWindowingMode()
+ : WINDOWING_MODE_UNDEFINED;
+ // hasInitialBounds is set if either activity options or layout has specified bounds. If
+ // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
+ boolean hasInitialBounds = false;
+ final boolean canApplyFreeformPolicy =
+ canApplyFreeformWindowPolicy(display, root, launchMode);
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(options) && canApplyFreeformPolicy) {
+ hasInitialBounds = true;
+ launchMode = launchMode == WINDOWING_MODE_UNDEFINED
+ ? WINDOWING_MODE_FREEFORM
+ : launchMode;
+ outParams.mBounds.set(options.getLaunchBounds());
+ if (DEBUG) appendLog("activity-options-bounds=" + outParams.mBounds);
+ } else if (launchMode == WINDOWING_MODE_PINNED) {
+ // System controls PIP window's bounds, so don't apply launch bounds.
+ if (DEBUG) appendLog("empty-window-layout-for-pip");
+ } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
+ if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
+ } else if (layout != null && canApplyFreeformPolicy) {
+ getLayoutBounds(display, root, layout, mTmpBounds);
+ if (!mTmpBounds.isEmpty()) {
+ launchMode = WINDOWING_MODE_FREEFORM;
+ outParams.mBounds.set(mTmpBounds);
+ hasInitialBounds = true;
+ if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
+ } else {
+ if (DEBUG) appendLog("empty-window-layout");
+ }
+ }
- final Rect resultBounds = outParams.mBounds;
+ // STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has
+ // some opinions on launch mode and launch bounds. If they have opinions and there is no
+ // initial bounds set in parameters. Note the check on display ID is also input param
+ // related because we always defer to callers' suggestion if there is no specific display ID
+ // in options or from source activity.
+ //
+ // If opinions from callers don't need any further resolution, we try to honor that as is as
+ // much as possible later.
+
+ // Flag to indicate if current param needs no further resolution. It's true it current
+ // param isn't freeform mode, or it already has launch bounds.
+ boolean fullyResolvedCurrentParam = false;
+ // We inherit launch params from previous modifiers or LaunchParamsController if options,
+ // layout and display conditions are not contradictory to their suggestions. It's important
+ // to carry over their values because LaunchParamsController doesn't automatically do that.
+ if (!currentParams.isEmpty() && !hasInitialBounds
+ && (!currentParams.hasPreferredDisplay()
+ || displayId == currentParams.mPreferredDisplayId)) {
+ if (currentParams.hasWindowingMode()) {
+ launchMode = currentParams.mWindowingMode;
+ fullyResolvedCurrentParam = (launchMode != WINDOWING_MODE_FREEFORM);
+ if (DEBUG) {
+ appendLog("inherit-" + WindowConfiguration.windowingModeToString(launchMode));
+ }
+ }
- if (layout == null) {
- positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
- getFreeformHeight(mAvailableRect), resultBounds);
- return RESULT_CONTINUE;
+ if (!currentParams.mBounds.isEmpty()) {
+ outParams.mBounds.set(currentParams.mBounds);
+ fullyResolvedCurrentParam = true;
+ if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+ }
}
- int width = getFinalWidth(layout, mAvailableRect);
- int height = getFinalHeight(layout, mAvailableRect);
- int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
- int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- if (verticalGravity == Gravity.TOP) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
- } else {
- positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
- }
- } else if (verticalGravity == Gravity.BOTTOM) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
- } else {
- positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
+ // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
+ // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
+ // are forced to be maximized. The rest of this step is to define the default policy when
+ // there is no initial bounds or a fully resolved current params from callers. Right now we
+ // launch all possible tasks/activities that can handle freeform into freeform mode.
+ if (display.inFreeformWindowingMode()) {
+ if (launchMode == WINDOWING_MODE_PINNED) {
+ if (DEBUG) appendLog("picture-in-picture");
+ } else if (isTaskForcedMaximized(root)) {
+ // We're launching an activity that probably can't handle resizing nicely, so force
+ // it to be maximized even someone suggests launching it in freeform using launch
+ // options.
+ launchMode = WINDOWING_MODE_FULLSCREEN;
+ outParams.mBounds.setEmpty();
+ if (DEBUG) appendLog("forced-maximize");
+ } else if (fullyResolvedCurrentParam) {
+ // Don't adjust launch mode if that's inherited, except when we're launching an
+ // activity that should be forced to maximize.
+ if (DEBUG) appendLog("skip-adjustment-fully-resolved-params");
+ } else if (launchMode != WINDOWING_MODE_FREEFORM
+ && (isNOrGreater(root) || isPreNResizeable(root))) {
+ // We're launching a pre-N and post-D activity that supports resizing, or a post-N
+ // activity. They can handle freeform nicely so launch them in freeform.
+ // Use undefined because we know we're in a freeform display.
+ launchMode = WINDOWING_MODE_UNDEFINED;
+ if (DEBUG) appendLog("should-be-freeform");
}
} else {
- // Some fancy gravity setting that we don't support yet. We just put the activity in the
- // center.
- Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
- + ", positioning in the center instead.");
- positionCenter(tasks, mAvailableRect, width, height, resultBounds);
+ if (DEBUG) appendLog("non-freeform-display");
+ }
+ // If launch mode matches display windowing mode, let it inherit from display.
+ outParams.mWindowingMode = launchMode == display.getWindowingMode()
+ ? WINDOWING_MODE_UNDEFINED : launchMode;
+
+ // STEP 3: Determine final launch bounds based on resolved windowing mode and activity
+ // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
+ // for all other windowing modes that's not freeform mode. One can read comments in
+ // relevant methods to further understand this step.
+ //
+ // We skip making adjustments if the params are fully resolved from previous results and
+ // trust that they are valid.
+ if (!fullyResolvedCurrentParam) {
+ final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
+ : display.getWindowingMode();
+ if (source != null && source.inFreeformWindowingMode()
+ && resolvedMode == WINDOWING_MODE_FREEFORM
+ && outParams.mBounds.isEmpty()
+ && source.getDisplayId() == display.mDisplayId) {
+ // Set bounds to be not very far from source activity.
+ cascadeBounds(source.getBounds(), display, outParams.mBounds);
+ }
+ getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
}
return RESULT_CONTINUE;
}
- @VisibleForTesting
- static int getFreeformStartLeft(Rect bounds) {
- return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR;
+ private int getPreferredLaunchDisplay(@Nullable ActivityOptions options,
+ ActivityRecord source, LaunchParams currentParams) {
+ int displayId = INVALID_DISPLAY;
+ final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
+ if (optionLaunchId != INVALID_DISPLAY) {
+ if (DEBUG) appendLog("display-from-option=" + optionLaunchId);
+ displayId = optionLaunchId;
+ }
+
+ if (displayId == INVALID_DISPLAY && source != null) {
+ final int sourceDisplayId = source.getDisplayId();
+ if (DEBUG) appendLog("display-from-source=" + sourceDisplayId);
+ displayId = sourceDisplayId;
+ }
+
+ if (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) == null) {
+ displayId = INVALID_DISPLAY;
+ }
+ displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
+
+ displayId = (displayId == INVALID_DISPLAY) ? DEFAULT_DISPLAY : displayId;
+
+ return displayId;
+ }
+
+ private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display,
+ @NonNull ActivityRecord root, int launchMode) {
+ return display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM
+ || root.isResizeable();
}
- @VisibleForTesting
- static int getFreeformStartTop(Rect bounds) {
- return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR;
+ private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+ @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+ final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+ final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
+ outBounds.setEmpty();
+ return;
+ }
+
+ final Rect bounds = display.getBounds();
+ final int defaultWidth = bounds.width();
+ final int defaultHeight = bounds.height();
+
+ int width;
+ int height;
+ if (!windowLayout.hasSpecifiedSize()) {
+ outBounds.setEmpty();
+ getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
+ /* hasInitialBounds */ false, outBounds);
+ width = outBounds.width();
+ height = outBounds.height();
+ } else {
+ width = defaultWidth;
+ if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
+ width = windowLayout.width;
+ } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) {
+ width = (int) (width * windowLayout.widthFraction);
+ }
+
+ height = defaultHeight;
+ if (windowLayout.height > 0 && windowLayout.height < defaultHeight) {
+ height = windowLayout.height;
+ } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) {
+ height = (int) (height * windowLayout.heightFraction);
+ }
+ }
+
+ final float fractionOfHorizontalOffset;
+ switch (horizontalGravity) {
+ case Gravity.LEFT:
+ fractionOfHorizontalOffset = 0f;
+ break;
+ case Gravity.RIGHT:
+ fractionOfHorizontalOffset = 1f;
+ break;
+ default:
+ fractionOfHorizontalOffset = 0.5f;
+ }
+
+ final float fractionOfVerticalOffset;
+ switch (verticalGravity) {
+ case Gravity.TOP:
+ fractionOfVerticalOffset = 0f;
+ break;
+ case Gravity.BOTTOM:
+ fractionOfVerticalOffset = 1f;
+ break;
+ default:
+ fractionOfVerticalOffset = 0.5f;
+ }
+
+ outBounds.set(0, 0, width, height);
+ final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
+ final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
+ outBounds.offset(xOffset, yOffset);
}
- @VisibleForTesting
- static int getFreeformWidth(Rect bounds) {
- return bounds.width() / WINDOW_SIZE_DENOMINATOR;
+ /**
+ * Returns if task is forced to maximize.
+ *
+ * There are several cases where we force a task to maximize:
+ * 1) Root activity is targeting pre-Donut, which by default can't handle multiple screen
+ * densities, so resizing will likely cause issues;
+ * 2) Root activity doesn't declare any flag that it supports any screen density, so resizing
+ * may also cause issues;
+ * 3) Root activity is not resizeable, for which we shouldn't allow user resize it.
+ *
+ * @param root the root activity to check against.
+ * @return {@code true} if it should be forced to maximize; {@code false} otherwise.
+ */
+ private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
+ if (root.appInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
+ || (root.appInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
+ return true;
+ }
+
+ return !root.isResizeable();
}
- @VisibleForTesting
- static int getFreeformHeight(Rect bounds) {
- return bounds.height() / WINDOW_SIZE_DENOMINATOR;
+ private boolean isNOrGreater(@NonNull ActivityRecord root) {
+ return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
+ }
+
+ /**
+ * Resolves activity requested orientation to 4 categories:
+ * 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
+ * orientation;
+ * 2) {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} indicating app wants to be in landscape;
+ * 3) {@link ActivityInfo#SCREEN_ORIENTATION_PORTRAIT} indicating app wants to be in portrait;
+ * 4) {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} indicating app can handle any
+ * orientation.
+ *
+ * @param activity the activity to check
+ * @return corresponding resolved orientation value.
+ */
+ private int resolveOrientation(@NonNull ActivityRecord activity) {
+ int orientation = activity.info.screenOrientation;
+ switch (orientation) {
+ case SCREEN_ORIENTATION_NOSENSOR:
+ case SCREEN_ORIENTATION_LOCKED:
+ orientation = SCREEN_ORIENTATION_LOCKED;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+ case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+ case SCREEN_ORIENTATION_USER_LANDSCAPE:
+ case SCREEN_ORIENTATION_LANDSCAPE:
+ if (DEBUG) appendLog("activity-requested-landscape");
+ orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+ case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+ case SCREEN_ORIENTATION_USER_PORTRAIT:
+ case SCREEN_ORIENTATION_PORTRAIT:
+ if (DEBUG) appendLog("activity-requested-portrait");
+ orientation = SCREEN_ORIENTATION_PORTRAIT;
+ break;
+ default:
+ orientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ return orientation;
}
- @VisibleForTesting
- static int getHorizontalStep(Rect bounds) {
- return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP);
+ private boolean isPreNResizeable(ActivityRecord root) {
+ return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
}
- @VisibleForTesting
- static int getVerticalStep(Rect bounds) {
- return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP);
+ private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+ @NonNull Rect outBounds) {
+ outBounds.set(srcBounds);
+ float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
+
+ display.getBounds(mTmpBounds);
+ final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
+ final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
+ outBounds.offset(dx, dy);
}
+ private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
+ @NonNull Rect inOutBounds) {
+ if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
+ // We don't handle letterboxing here. Letterboxing will be handled by valid checks
+ // later.
+ inOutBounds.setEmpty();
+ if (DEBUG) appendLog("maximized-bounds");
+ return;
+ }
+ if (resolvedMode != WINDOWING_MODE_FREEFORM) {
+ // We don't apply freeform bounds adjustment to other windowing modes.
+ if (DEBUG) {
+ appendLog("skip-bounds-" + WindowConfiguration.windowingModeToString(resolvedMode));
+ }
+ return;
+ }
- private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int width = getFreeformWidth(availableRect);
- if (windowLayout.width > 0) {
- width = windowLayout.width;
+ final int orientation = resolveOrientation(root, display, inOutBounds);
+ if (orientation != SCREEN_ORIENTATION_PORTRAIT
+ && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
+ throw new IllegalStateException(
+ "Orientation must be one of portrait or landscape, but it's "
+ + ActivityInfo.screenOrientationToString(orientation));
}
- if (windowLayout.widthFraction > 0) {
- width = (int) (availableRect.width() * windowLayout.widthFraction);
+
+ // First we get the default size we want.
+ getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+ if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
+ // We're here because either input parameters specified initial bounds, or the suggested
+ // bounds have the same size of the default freeform size. We should use the suggested
+ // bounds if possible -- so if app can handle the orientation we just use it, and if not
+ // we transpose the suggested bounds in-place.
+ if (orientation == orientationFromBounds(inOutBounds)) {
+ if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
+ } else {
+ // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
+ centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+ if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
+ }
+ } else {
+ // We are here either because there is no suggested bounds, or the suggested bounds is
+ // a cascade from source activity. We should use the default freeform size and center it
+ // to the center of suggested bounds (or the display if no suggested bounds). The
+ // default size might be too big to center to source activity bounds in display, so we
+ // may need to move it back to the display.
+ centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
+ adjustBoundsToFitInDisplay(display, inOutBounds);
+ if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
}
- return width;
+
+ // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
+ adjustBoundsToAvoidConflict(display, inOutBounds);
}
- private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int height = getFreeformHeight(availableRect);
- if (windowLayout.height > 0) {
- height = windowLayout.height;
+ private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull Rect bounds) {
+ int orientation = resolveOrientation(root);
+
+ if (orientation == SCREEN_ORIENTATION_LOCKED) {
+ orientation = bounds.isEmpty() ? display.getConfiguration().orientation
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
+ : "locked-orientation-from-bounds=" + bounds);
+ }
}
- if (windowLayout.heightFraction > 0) {
- height = (int) (availableRect.height() * windowLayout.heightFraction);
+
+ if (orientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ orientation = bounds.isEmpty() ? SCREEN_ORIENTATION_PORTRAIT
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "default-portrait"
+ : "orientation-from-bounds=" + bounds);
+ }
}
- return height;
- }
- private void positionBottomLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.bottom - height,
- availableRect.left + width, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
+ return orientation;
}
- private void positionBottomRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
- availableRect.right, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
+ private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+ @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
+ // Default size, which is letterboxing/pillarboxing in display. That's to say the large
+ // dimension of default size is the small dimension of display size, and the small dimension
+ // of default size is calculated to keep the same aspect ratio as the display's.
+ Rect displayBounds = display.getBounds();
+ final int portraitHeight = Math.min(displayBounds.width(), displayBounds.height());
+ final int otherDimension = Math.max(displayBounds.width(), displayBounds.height());
+ final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
+ final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
+ : portraitWidth;
+ final int defaultHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitWidth
+ : portraitHeight;
+
+ // Get window size based on Nexus 5x screen, we assume that this is enough to show content
+ // of activities.
+ final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
+ final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
+ final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
+ : phonePortraitWidth;
+ final int phoneHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitWidth
+ : phonePortraitHeight;
+
+ // Minimum layout requirements.
+ final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth;
+ final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
+
+ // Final result.
+ final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
+ final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
+
+ bounds.set(0, 0, width, height);
}
- private void positionTopLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.top,
- availableRect.left + width, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
+ /**
+ * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
+ * centers at its center or display's center if inOutBounds is empty.
+ */
+ private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+ @NonNull Rect inOutBounds) {
+ if (inOutBounds.isEmpty()) {
+ display.getBounds(inOutBounds);
+ }
+ final int left = inOutBounds.centerX() - width / 2;
+ final int top = inOutBounds.centerY() - height / 2;
+ inOutBounds.set(left, top, left + width, top + height);
}
- private void positionTopRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.top,
- availableRect.right, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
- }
+ private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+
+ if (displayBounds.width() < inOutBounds.width()
+ || displayBounds.height() < inOutBounds.height()) {
+ // There is no way for us to fit the bounds in the display without changing width
+ // or height. Don't even try it.
+ return;
+ }
+
+ final int dx;
+ if (inOutBounds.right > displayBounds.right) {
+ // Right edge is out of display.
+ dx = displayBounds.right - inOutBounds.right;
+ } else if (inOutBounds.left < displayBounds.left) {
+ // Left edge is out of display.
+ dx = displayBounds.left - inOutBounds.left;
+ } else {
+ // Vertical edges are all in display.
+ dx = 0;
+ }
- private void positionCenter(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
- final int defaultFreeformTop = getFreeformStartTop(availableRect);
- mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
- defaultFreeformLeft + width, defaultFreeformTop + height);
- position(tasks, availableRect, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN,
- result);
+ final int dy;
+ if (inOutBounds.top < displayBounds.top) {
+ // Top edge is out of display.
+ dy = displayBounds.top - inOutBounds.top;
+ } else if (inOutBounds.bottom > displayBounds.bottom) {
+ // Bottom edge is out of display.
+ dy = displayBounds.bottom - inOutBounds.bottom;
+ } else {
+ // Horizontal edges are all in display.
+ dy = 0;
+ }
+ inOutBounds.offset(dx, dy);
}
- private void position(ArrayList<TaskRecord> tasks, Rect availableRect,
- Rect proposal, boolean allowRestart, int shiftPolicy, Rect result) {
- mTmpOriginal.set(proposal);
- boolean restarted = false;
- while (boundsConflict(proposal, tasks)) {
- // Unfortunately there is already a task at that spot, so we need to look for some
- // other place.
- shiftStartingPoint(proposal, availableRect, shiftPolicy);
- if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
- // We don't want the task to go outside of the stack, because it won't look
- // nice. Depending on the starting point we either restart, or immediately give up.
- if (!allowRestart) {
- proposal.set(mTmpOriginal);
- break;
- }
- // We must have started not from the top. Let's restart from there because there
- // might be some space there.
- proposal.set(availableRect.left, availableRect.top,
- availableRect.left + proposal.width(),
- availableRect.top + proposal.height());
- restarted = true;
+ /**
+ * Adjusts input bounds to avoid conflict with existing tasks in the display.
+ *
+ * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
+ * directions to find a location where the we can put the bounds in display without conflict
+ * with any other tasks.
+ *
+ * It doesn't try to adjust bounds that's not fully in the given display.
+ *
+ * @param display the display which tasks are to check
+ * @param inOutBounds the bounds used to input initial bounds and output result bounds
+ */
+ private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+ if (!displayBounds.contains(inOutBounds)) {
+ // The initial bounds are already out of display. The scanning algorithm below doesn't
+ // work so well with them.
+ return;
+ }
+
+ final List<TaskRecord> tasksToCheck = new ArrayList<>();
+ for (int i = 0; i < display.getChildCount(); ++i) {
+ ActivityStack<?> stack = display.getChildAt(i);
+ if (!stack.inFreeformWindowingMode()) {
+ continue;
}
- if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
- || proposal.top > getFreeformStartTop(availableRect))) {
- // If we restarted and crossed the initial position, let's not struggle anymore.
- // The user already must have ton of tasks visible, we can just smack the new
- // one in the center.
- proposal.set(mTmpOriginal);
+
+ for (int j = 0; j < stack.getChildCount(); ++j) {
+ tasksToCheck.add(stack.getChildAt(j));
+ }
+ }
+
+ if (!boundsConflict(tasksToCheck, inOutBounds)) {
+ // Current proposal doesn't conflict with any task. Early return to avoid unnecessary
+ // calculation.
+ return;
+ }
+
+ calculateCandidateShiftDirections(displayBounds, inOutBounds);
+ for (int direction : mTmpDirections) {
+ if (direction == Gravity.NO_GRAVITY) {
+ // We exhausted candidate directions, give up.
break;
}
+
+ mTmpBounds.set(inOutBounds);
+ while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ shiftBounds(direction, displayBounds, mTmpBounds);
+ }
+
+ if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ // Found a candidate. Just use this.
+ inOutBounds.set(mTmpBounds);
+ if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
+ return;
+ }
+
+ // Didn't find a conflict free bounds here. Try the next candidate direction.
}
- result.set(proposal);
+
+ // We failed to find a conflict free location. Just keep the original result.
}
- private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- return start.left < availableRect.left;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- return start.right > availableRect.right;
- default: // SHIFT_POLICY_DIAGONAL_DOWN
- return start.right > availableRect.right || start.bottom > availableRect.bottom;
+ /**
+ * Determines scanning directions and their priorities to avoid bounds conflict.
+ *
+ * @param availableBounds bounds that the result must be in
+ * @param initialBounds initial bounds when start scanning
+ */
+ private void calculateCandidateShiftDirections(@NonNull Rect availableBounds,
+ @NonNull Rect initialBounds) {
+ for (int i = 0; i < mTmpDirections.length; ++i) {
+ mTmpDirections[i] = Gravity.NO_GRAVITY;
+ }
+
+ final int oneThirdWidth = (2 * availableBounds.left + availableBounds.right) / 3;
+ final int twoThirdWidth = (availableBounds.left + 2 * availableBounds.right) / 3;
+ final int centerX = initialBounds.centerX();
+ if (centerX < oneThirdWidth) {
+ // Too close to left, just scan to the right.
+ mTmpDirections[0] = Gravity.RIGHT;
+ return;
+ } else if (centerX > twoThirdWidth) {
+ // Too close to right, just scan to the left.
+ mTmpDirections[0] = Gravity.LEFT;
+ return;
}
+
+ final int oneThirdHeight = (2 * availableBounds.top + availableBounds.bottom) / 3;
+ final int twoThirdHeight = (availableBounds.top + 2 * availableBounds.bottom) / 3;
+ final int centerY = initialBounds.centerY();
+ if (centerY < oneThirdHeight || centerY > twoThirdHeight) {
+ // Too close to top or bottom boundary and we're in the middle horizontally, scan
+ // horizontally in both directions.
+ mTmpDirections[0] = Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.LEFT;
+ return;
+ }
+
+ // We're in the center region both horizontally and vertically. Scan in both directions of
+ // primary diagonal.
+ mTmpDirections[0] = Gravity.BOTTOM | Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.TOP | Gravity.LEFT;
}
- private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
- final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
- final int defaultFreeformStepVertical = getVerticalStep(availableRect);
+ private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) {
+ for (TaskRecord task : tasks) {
+ final Rect taskBounds = task.getBounds();
+ final boolean leftClose = Math.abs(taskBounds.left - bounds.left)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean topClose = Math.abs(taskBounds.top - bounds.top)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean rightClose = Math.abs(taskBounds.right - bounds.right)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom)
+ < BOUNDS_CONFLICT_THRESHOLD;
+
+ if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose)
+ || (rightClose && bottomClose)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- posposal.offset(-defaultFreeformStepHorizontal, 0);
+ private void shiftBounds(int direction, @NonNull Rect availableRect,
+ @NonNull Rect inOutBounds) {
+ final int horizontalOffset;
+ switch (direction & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ horizontalOffset = -Math.max(MINIMAL_STEP,
+ availableRect.width() / STEP_DENOMINATOR);
break;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- posposal.offset(defaultFreeformStepHorizontal, 0);
+ case Gravity.RIGHT:
+ horizontalOffset = Math.max(MINIMAL_STEP, availableRect.width() / STEP_DENOMINATOR);
break;
- default: // SHIFT_POLICY_DIAGONAL_DOWN:
- posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
+ default:
+ horizontalOffset = 0;
+ }
+
+ final int verticalOffset;
+ switch (direction & Gravity.VERTICAL_GRAVITY_MASK) {
+ case Gravity.TOP:
+ verticalOffset = -Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
break;
+ case Gravity.BOTTOM:
+ verticalOffset = Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+ break;
+ default:
+ verticalOffset = 0;
}
+
+ inOutBounds.offset(horizontalOffset, verticalOffset);
}
- private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final TaskRecord task = tasks.get(i);
- if (!task.mActivities.isEmpty() && !task.matchParentBounds()) {
- final Rect bounds = task.getOverrideBounds();
- if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
- || closeLeftBottomCorner(proposal, bounds)
- || closeRightBottomCorner(proposal, bounds)) {
- return true;
- }
- }
+ private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+ if (DEBUG) {
+ mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
+ + " activity=" + activity);
}
- return false;
}
- private static final boolean closeLeftTopCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void appendLog(String log) {
+ if (DEBUG) mLogBuilder.append(" ").append(log);
}
- private static final boolean closeRightTopCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void outputLog() {
+ if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
}
- private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private static int orientationFromBounds(Rect bounds) {
+ return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
}
- private static final boolean closeRightBottomCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private static boolean sizeMatches(Rect left, Rect right) {
+ return (Math.abs(right.width() - left.width()) < EPSILON)
+ && (Math.abs(right.height() - left.height()) < EPSILON);
}
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 05b0d598f878..5f5916331e67 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -45,16 +46,16 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-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.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
@@ -129,7 +130,7 @@ import java.util.Objects;
// TODO: Make package private again once move to WM package is complete.
public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
@@ -172,7 +173,6 @@ public class TaskRecord extends ConfigurationContainer implements TaskWindowCont
// code.
private static final int PERSIST_TASK_VERSION = 1;
- static final int INVALID_TASK_ID = -1;
private static final int INVALID_MIN_SIZE = -1;
/**
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index 366f95a170ff..51d86d66e6c1 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -248,9 +248,9 @@ final class VrController {
*
* @param tid the tid of the thread to set, or 0 to unset the current thread.
* @param pid the pid of the process owning the thread to set.
- * @param proc the ProcessRecord of the process owning the thread to set.
+ * @param proc the process owning the thread to set.
*/
- public void setPersistentVrThreadLocked(int tid, int pid, ProcessRecord proc) {
+ public void setPersistentVrThreadLocked(int tid, int pid, WindowProcessController proc) {
if (!hasPersistentVrFlagSet()) {
Slog.w(TAG, "Persistent VR thread may only be set in persistent VR mode!");
return;
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index f6f4db6a2d37..a461d1c4b849 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -18,12 +18,12 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-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.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
@@ -63,7 +63,7 @@ import java.util.ArrayList;
* calls are allowed to proceed.
*/
public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer> {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_AM;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_ATM;
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
@@ -87,6 +87,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private volatile IApplicationThread mThread;
// Currently desired scheduling class
private volatile int mCurSchedGroup;
+ // Currently computed process state
+ private volatile int mCurProcState = PROCESS_STATE_NONEXISTENT;
// Last reported process state;
private volatile int mRepProcState = PROCESS_STATE_NONEXISTENT;
// are we in the process of crashing?
@@ -99,6 +101,28 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private volatile String mRequiredAbi;
// Running any services that are foreground?
private volatile boolean mHasForegroundServices;
+ // Running any activities that are foreground?
+ private volatile boolean mHasForegroundActivities;
+ // Are there any client services with activities?
+ private volatile boolean mHasClientActivities;
+ // Is this process currently showing a non-activity UI that the user is interacting with?
+ // E.g. The status bar when it is expanded, but not when it is minimized. When true the process
+ // will be set to use the ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost performance.
+ private volatile boolean mHasTopUi;
+ // Is the process currently showing a non-activity UI that overlays on-top of activity UIs on
+ // screen. E.g. display a window of type
+ // android.view.WindowManager.LayoutParams#TYPE_APPLICATION_OVERLAY When true the process will
+ // oom adj score will be set to ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance
+ // of the process getting killed.
+ private volatile boolean mHasOverlayUi;
+ // Want to clean up resources from showing UI?
+ private volatile boolean mPendingUiClean;
+ // The time we sent the last interaction event
+ private volatile long mInteractionEventTime;
+ // When we became foreground for interaction purposes
+ private volatile long mFgInteractionTime;
+ // When (uptime) the process last became unimportant
+ private volatile long mWhenUnimportant;
// was app launched for debugging?
private volatile boolean mDebugging;
// Active instrumentation running in process?
@@ -161,6 +185,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mCurSchedGroup;
}
+ public void setCurrentProcState(int curProcState) {
+ mCurProcState = curProcState;
+ }
+
+ int getCurrentProcState() {
+ return mCurProcState;
+ }
+
public void setReportedProcState(int repProcState) {
mRepProcState = repProcState;
}
@@ -201,6 +233,78 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mHasForegroundServices;
}
+ public void setHasForegroundActivities(boolean hasForegroundActivities) {
+ mHasForegroundActivities = hasForegroundActivities;
+ }
+
+ boolean hasForegroundActivities() {
+ return mHasForegroundActivities;
+ }
+
+ public void setHasClientActivities(boolean hasClientActivities) {
+ mHasClientActivities = hasClientActivities;
+ }
+
+ boolean hasClientActivities() {
+ return mHasClientActivities;
+ }
+
+ public void setHasTopUi(boolean hasTopUi) {
+ mHasTopUi = hasTopUi;
+ }
+
+ boolean hasTopUi() {
+ return mHasTopUi;
+ }
+
+ public void setHasOverlayUi(boolean hasOverlayUi) {
+ mHasOverlayUi = hasOverlayUi;
+ }
+
+ boolean hasOverlayUi() {
+ return mHasOverlayUi;
+ }
+
+ public void setPendingUiClean(boolean hasPendingUiClean) {
+ mPendingUiClean = hasPendingUiClean;
+ }
+
+ boolean hasPendingUiClean() {
+ return mPendingUiClean;
+ }
+
+ void postPendingUiCleanMsg(boolean pendingUiClean) {
+ if (mListener == null) return;
+ // Posting on handler so WM lock isn't held when we call into AM.
+ final Message m = PooledLambda.obtainMessage(
+ WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
+ mAtm.mH.sendMessage(m);
+ }
+
+ public void setInteractionEventTime(long interactionEventTime) {
+ mInteractionEventTime = interactionEventTime;
+ }
+
+ long getInteractionEventTime() {
+ return mInteractionEventTime;
+ }
+
+ public void setFgInteractionTime(long fgInteractionTime) {
+ mFgInteractionTime = fgInteractionTime;
+ }
+
+ long getFgInteractionTime() {
+ return mFgInteractionTime;
+ }
+
+ public void setWhenUnimportant(long whenUnimportant) {
+ mWhenUnimportant = whenUnimportant;
+ }
+
+ long getWhenUnimportant() {
+ return mWhenUnimportant;
+ }
+
public void setRequiredAbi(String requiredAbi) {
mRequiredAbi = requiredAbi;
}
@@ -532,14 +636,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
WindowProcessListener::updateServiceConnectionActivities, mListener));
}
- void setPendingUiClean(boolean pendingUiClean) {
- if (mListener == null) return;
- // Posting on handler so WM lock isn't held when we call into AM.
- final Message m = PooledLambda.obtainMessage(
- WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
- mAtm.mH.sendMessage(m);
- }
-
void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index bdbb0a40d797..61836fdd7316 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -27,6 +27,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.security.KeyStore;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.statusbar.IStatusBarService;
@@ -205,6 +206,16 @@ public abstract class AuthenticationClient extends ClientMonitor {
return super.onError(deviceId, error, vendorCode);
}
+ public void setTitleIfEmpty(CharSequence title) {
+ if (TextUtils.isEmpty(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
+ mBundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
+ }
+ }
+
+ public boolean isBiometricPrompt() {
+ return mBundle != null;
+ }
+
private void notifyClientAuthenticationSucceeded(BiometricAuthenticator.Identifier identifier)
throws RemoteException {
final BiometricServiceBase.ServiceListener listener = getListener();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 3d2f5677cafb..b80dca6019fa 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -29,6 +29,7 @@ import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricPromptReceiver;
@@ -239,7 +240,7 @@ public class BiometricService extends SystemService {
* should not carry any state. The reality is we need to keep a tiny amount of state so that
* cancelAuthentication() can go to the right place.
*/
- private final class BiometricPromptServiceWrapper extends IBiometricService.Stub {
+ private final class BiometricServiceWrapper extends IBiometricService.Stub {
@Override // Binder call
public void authenticate(IBinder token, long sessionId, int userId,
@@ -255,6 +256,12 @@ public class BiometricService extends SystemService {
return;
}
+ // Check the usage of this in system server. Need to remove this check if it becomes
+ // a public API.
+ if (bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)) {
+ checkInternalPermission();
+ }
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
@@ -363,7 +370,7 @@ public class BiometricService extends SystemService {
return error;
}
- @Override
+ @Override // Binder call
public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
throws RemoteException {
checkInternalPermission();
@@ -375,6 +382,19 @@ public class BiometricService extends SystemService {
Slog.w(TAG, "Remote exception", e);
}
}
+
+ @Override // Binder call
+ public void setActiveUser(int userId) {
+ checkInternalPermission();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ for (int i = 0; i < mAuthenticators.size(); i++) {
+ mAuthenticators.get(i).getAuthenticator().setActiveUser(userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private void checkAppOp(String opPackageName, int callingUid) {
@@ -387,7 +407,7 @@ public class BiometricService extends SystemService {
private void checkInternalPermission() {
getContext().enforceCallingPermission(USE_BIOMETRIC_INTERNAL,
- "Must have MANAGE_BIOMETRIC permission");
+ "Must have USE_BIOMETRIC_INTERNAL permission");
}
private void checkPermission() {
@@ -455,7 +475,7 @@ public class BiometricService extends SystemService {
}
}
- publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricPromptServiceWrapper());
+ publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper());
}
/**
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 71bf56085452..74d742af5b84 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -16,6 +16,7 @@
package com.android.server.biometrics;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
import android.app.ActivityManager;
@@ -55,6 +56,7 @@ import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
@@ -704,6 +706,30 @@ public abstract class BiometricServiceBase extends SystemService
}
mHandler.post(() -> {
+ if (client.isBiometricPrompt()) {
+ try {
+ final List<ActivityManager.RunningAppProcessInfo> procs =
+ ActivityManager.getService().getRunningAppProcesses();
+ for (int i = 0; i < procs.size(); i++) {
+ final ActivityManager.RunningAppProcessInfo info = procs.get(i);
+ if (info.uid == callingUid && info.importance == IMPORTANCE_FOREGROUND) {
+ PackageManager pm = getContext().getPackageManager();
+ final CharSequence label = pm.getApplicationLabel(
+ pm.getApplicationInfo(info.processName,
+ PackageManager.GET_META_DATA));
+ final String title = getContext()
+ .getString(R.string.biometric_dialog_default_title, label);
+ client.setTitleIfEmpty(title);
+ break;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get application name", e);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(getTag(), "Unable to get application name", e);
+ }
+ }
+
mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
// Get performance stats object for this user.
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ca9b25699c1c..30659c1e77a3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1031,6 +1031,11 @@ public class NetworkMonitor extends StateMachine {
result.isPortal() /* isCaptivePortal */,
startTime, endTime);
+ log("isCaptivePortal: isSuccessful()=" + result.isSuccessful() +
+ " isPortal()=" + result.isPortal() +
+ " RedirectUrl=" + result.redirectUrl +
+ " StartTime=" + startTime + " EndTime=" + endTime);
+
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index b7bbd422458f..15468ff05c08 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,6 +16,12 @@
package com.android.server.connectivity;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.provider.Settings.Global.HTTP_PROXY;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -47,16 +53,14 @@ public class ProxyTracker {
@NonNull
private final Context mContext;
- // TODO : make this private and import as much managing logic from ConnectivityService as
- // possible
@NonNull
- public final Object mProxyLock = new Object();
+ private final Object mProxyLock = new Object();
// The global proxy is the proxy that is set device-wide, overriding any network-specific
// proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
// this value is only for querying.
@Nullable
@GuardedBy("mProxyLock")
- public ProxyInfo mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
// The default proxy is the proxy that applies to no particular network if the global proxy
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
@@ -64,10 +68,10 @@ public class ProxyTracker {
// when PacManager resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
- public volatile ProxyInfo mDefaultProxy = null;
- // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+ private volatile ProxyInfo mDefaultProxy = null;
+ // Whether the default proxy is enabled.
@GuardedBy("mProxyLock")
- public boolean mDefaultProxyDisabled = false;
+ private boolean mDefaultProxyEnabled = true;
// The object responsible for Proxy Auto Configuration (PAC).
@NonNull
@@ -85,7 +89,7 @@ public class ProxyTracker {
@Nullable
private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+ && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
return null;
}
return proxy;
@@ -122,9 +126,9 @@ public class ProxyTracker {
public ProxyInfo getDefaultProxy() {
// This information is already available as a world read/writable jvm property.
synchronized (mProxyLock) {
- final ProxyInfo ret = mGlobalProxy;
- if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
- return ret;
+ if (mGlobalProxy != null) return mGlobalProxy;
+ if (mDefaultProxyEnabled) return mDefaultProxy;
+ return null;
}
}
@@ -146,11 +150,10 @@ public class ProxyTracker {
*/
public void loadGlobalProxy() {
ContentResolver res = mContext.getContentResolver();
- String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
- int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
- String exclList = Settings.Global.getString(res,
- Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+ String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
@@ -167,19 +170,44 @@ public class ProxyTracker {
mGlobalProxy = proxyProperties;
}
}
+ loadDeprecatedGlobalHttpProxy();
// TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
}
/**
+ * Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
+ */
+ public void loadDeprecatedGlobalHttpProxy() {
+ final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
+ if (!TextUtils.isEmpty(proxy)) {
+ String data[] = proxy.split(":");
+ if (data.length == 0) {
+ return;
+ }
+
+ final String proxyHost = data[0];
+ int proxyPort = 8080;
+ if (data.length > 1) {
+ try {
+ proxyPort = Integer.parseInt(data[1]);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ }
+ final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
+ setGlobalProxy(p);
+ }
+ }
+
+ /**
* Sends the system broadcast informing apps about a new proxy configuration.
*
* Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
* to do in a "sendProxyBroadcast" method.
- * @param proxyInfo the proxy spec, or null for no proxy.
*/
- // TODO : make the argument NonNull final and the method private
- public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) {
- if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, "");
+ public void sendProxyBroadcast() {
+ final ProxyInfo defaultProxy = getDefaultProxy();
+ final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
@@ -232,16 +260,15 @@ public class ProxyTracker {
final ContentResolver res = mContext.getContentResolver();
final long token = Binder.clearCallingIdentity();
try {
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
} finally {
Binder.restoreCallingIdentity(token);
}
- sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo);
+ sendProxyBroadcast();
}
}
@@ -253,10 +280,7 @@ public class ProxyTracker {
*/
public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
synchronized (mProxyLock) {
- if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
- return;
- }
- if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+ if (Objects.equals(mDefaultProxy, proxyInfo)) return;
if (proxyInfo != null && !proxyInfo.isValid()) {
if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
@@ -271,14 +295,32 @@ public class ProxyTracker {
&& (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
&& proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
mGlobalProxy = proxyInfo;
- sendProxyBroadcast(mGlobalProxy);
+ sendProxyBroadcast();
return;
}
mDefaultProxy = proxyInfo;
if (mGlobalProxy != null) return;
- if (!mDefaultProxyDisabled) {
- sendProxyBroadcast(proxyInfo);
+ if (mDefaultProxyEnabled) {
+ sendProxyBroadcast();
+ }
+ }
+ }
+
+ /**
+ * Enable or disable the default proxy.
+ *
+ * This sets the flag for enabling/disabling the default proxy and sends the broadcast
+ * if applicable.
+ * @param enabled whether the default proxy should be enabled.
+ */
+ public void setDefaultProxyEnabled(final boolean enabled) {
+ synchronized (mProxyLock) {
+ if (mDefaultProxyEnabled != enabled) {
+ mDefaultProxyEnabled = enabled;
+ if (mGlobalProxy == null && mDefaultProxy != null) {
+ sendProxyBroadcast();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 71c419f50790..991ecb8ea3dd 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1788,10 +1788,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- private boolean verifyDisplayId(ClientState cs) {
- return mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid);
- }
-
void removeClient(IInputMethodClient client) {
synchronized (mMethodMap) {
ClientState cs = mClients.remove(client.asBinder());
@@ -2008,12 +2004,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
com.android.internal.R.string.input_method_binding_label);
mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
- if (!verifyDisplayId(mCurFocusedWindowClient)) {
- // Wait, the client no longer has access to the display.
- return InputBindResult.INVALID_DISPLAY_ID;
+
+ if (mCurFocusedWindowClient == null) {
+ // This can happen when called from systemRunning() or switchUserLocked(). In this case,
+ // there really isn't an actual client yet. Let IME be on the default display.
+ // TODO(Bug 117730713): Check if really need to bind to the IME or not.
+ mCurTokenDisplayId = DEFAULT_DISPLAY;
+ } else {
+ if (!mWindowManagerInternal.isUidAllowedOnDisplay(
+ mCurFocusedWindowClient.selfReportedDisplayId, mCurFocusedWindowClient.uid)) {
+ // Wait, the client no longer has access to the display.
+ return InputBindResult.INVALID_DISPLAY_ID;
+ }
+ final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
+ mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
}
- final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
- mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
mLastBindTime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 389782a91d06..dd993b842aca 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -877,14 +877,17 @@ public class JobSchedulerService extends com.android.server.SystemService
// This may throw a SecurityException.
jobStatus.prepareLocked(ActivityManager.getService());
- if (toCancel != null) {
- cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
- }
if (work != null) {
// If work has been supplied, enqueue it into the new job.
jobStatus.enqueueWorkLocked(ActivityManager.getService(), work);
}
- startTrackingJobLocked(jobStatus, toCancel);
+
+ if (toCancel != null) {
+ // Implicitly replaces the existing job record with the new instance
+ cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
+ } else {
+ startTrackingJobLocked(jobStatus, null);
+ }
StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
uId, null, jobStatus.getBatteryName(),
StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
@@ -1013,6 +1016,12 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
+ /**
+ * Cancel the given job, stopping it if it's currently executing. If {@code incomingJob}
+ * is null, the cancelled job is removed outright from the system. If
+ * {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of
+ * currently scheduled jobs.
+ */
private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
cancelled.unprepareLocked(ActivityManager.getService());
@@ -1023,6 +1032,11 @@ public class JobSchedulerService extends com.android.server.SystemService
}
// Cancel if running.
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);
+ // If this is a replacement, bring in the new version of the job
+ if (incomingJob != null) {
+ if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
+ startTrackingJobLocked(incomingJob, cancelled);
+ }
reportActiveLocked();
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 9640e042fe6a..b29b7cf5a712 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -76,6 +76,13 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
*/
private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);
+ /*
+ * Internal interface used to invoke client callbacks.
+ */
+ private interface CallbackConsumer {
+ void accept(IContextHubClientCallback callback) throws RemoteException;
+ }
+
/* package */ ContextHubClientBroker(
Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
int contextHubId, short hostEndPointId, IContextHubClientCallback callback) {
@@ -140,12 +147,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
/**
* Invoked when the underlying binder of this broker has died at the client process.
*/
+ @Override
public void binderDied() {
- try {
- IContextHubClient.Stub.asInterface(this).close();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while closing client on death", e);
- }
+ close();
}
/**
@@ -168,14 +172,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
* @param message the message that came from a nanoapp
*/
/* package */ void sendMessageToClient(NanoAppMessage message) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onMessageFromNanoApp(message);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while sending message to client (host endpoint ID = "
- + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onMessageFromNanoApp(message));
}
/**
@@ -184,14 +181,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
* @param nanoAppId the ID of the nanoapp that was loaded.
*/
/* package */ void onNanoAppLoaded(long nanoAppId) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onNanoAppLoaded(nanoAppId);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppLoaded on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onNanoAppLoaded(nanoAppId));
}
/**
@@ -200,28 +190,14 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
* @param nanoAppId the ID of the nanoapp that was unloaded.
*/
/* package */ void onNanoAppUnloaded(long nanoAppId) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onNanoAppUnloaded(nanoAppId);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppUnloaded on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onNanoAppUnloaded(nanoAppId));
}
/**
* Notifies the client of a hub reset event if the connection is open.
*/
/* package */ void onHubReset() {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onHubReset();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onHubReset on client" +
- " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onHubReset());
}
/**
@@ -231,12 +207,21 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
* @param abortCode the nanoapp specific abort code
*/
/* package */ void onNanoAppAborted(long nanoAppId, int abortCode) {
+ invokeCallbackConcurrent(callback -> callback.onNanoAppAborted(nanoAppId, abortCode));
+ }
+
+ /**
+ * Helper function to invoke a specified client callback, if the connection is open.
+ *
+ * @param consumer the consumer specifying the callback to invoke
+ */
+ private void invokeCallbackConcurrent(CallbackConsumer consumer) {
if (mConnectionOpen.get()) {
try {
- mCallbackInterface.onNanoAppAborted(nanoAppId, abortCode);
+ consumer.accept(mCallbackInterface);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppAborted on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
+ Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
+ + mHostEndPointId + ")", e);
}
}
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 31cf9e346195..53d54ba11e99 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -254,6 +254,9 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
// Default update duration in milliseconds for REQUEST_LOCATION.
private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
+ // Default time limit in milliseconds for the ConnectivityManager to find a suitable
+ // network with SUPL connectivity or report an error.
+ private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
/** simpler wrapper for ProviderRequest + Worksource */
private static class GpsRequest {
@@ -539,14 +542,23 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
+ if (DEBUG) Log.d(TAG, "SUPL network connection available.");
// Specific to a change to a SUPL enabled network becoming ready
sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
}
@Override
public void onLost(Network network) {
+ Log.i(TAG, "SUPL network connection lost.");
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
}
+
+ @Override
+ public void onUnavailable() {
+ Log.i(TAG, "SUPL network connection request timed out.");
+ // Could not setup the connection to the network in the specified time duration.
+ releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+ }
};
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -953,7 +965,8 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
NetworkRequest request = requestBuilder.build();
mConnMgr.requestNetwork(
request,
- mSuplConnectivityCallback);
+ mSuplConnectivityCallback,
+ SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
}
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
@@ -2796,4 +2809,3 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
}
-
diff --git a/services/core/java/com/android/server/media/MediaUpdateService.java b/services/core/java/com/android/server/media/MediaUpdateService.java
index af06d157a526..7304f0788a1d 100644
--- a/services/core/java/com/android/server/media/MediaUpdateService.java
+++ b/services/core/java/com/android/server/media/MediaUpdateService.java
@@ -22,7 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.media.IMediaExtractorUpdateService;
+import android.media.IMediaUpdateService;
import android.os.Build;
import android.os.IBinder;
import android.os.Handler;
@@ -34,6 +34,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import com.android.server.SystemService;
+import java.util.HashMap;
/** This class provides a system service that manages media framework updates. */
public class MediaUpdateService extends SystemService {
@@ -42,34 +43,40 @@ public class MediaUpdateService extends SystemService {
private static final String MEDIA_UPDATE_PACKAGE_NAME =
SystemProperties.get("ro.mediacomponents.package");
private static final String EXTRACTOR_UPDATE_SERVICE_NAME = "media.extractor.update";
-
- private IMediaExtractorUpdateService mMediaExtractorUpdateService;
- final Handler mHandler;
+ private static final String CODEC_UPDATE_SERVICE_NAME = "media.codec.update";
+ private static final String[] UPDATE_SERVICE_NAME_ARRAY = {
+ EXTRACTOR_UPDATE_SERVICE_NAME, CODEC_UPDATE_SERVICE_NAME,
+ };
+ private final HashMap<String, IMediaUpdateService> mUpdateServiceMap = new HashMap<>();
+ private final Handler mHandler = new Handler();
public MediaUpdateService(Context context) {
super(context);
- mHandler = new Handler();
}
@Override
public void onStart() {
if (("userdebug".equals(android.os.Build.TYPE) || "eng".equals(android.os.Build.TYPE))
&& !TextUtils.isEmpty(MEDIA_UPDATE_PACKAGE_NAME)) {
- connect();
+ for (String serviceName : UPDATE_SERVICE_NAME_ARRAY) {
+ connect(serviceName);
+ }
registerBroadcastReceiver();
}
}
- private void connect() {
- IBinder binder = ServiceManager.getService(EXTRACTOR_UPDATE_SERVICE_NAME);
+ private void connect(final String serviceName) {
+ IBinder binder = ServiceManager.getService(serviceName);
if (binder != null) {
try {
binder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- Slog.w(TAG, "mediaextractor died; reconnecting");
- mMediaExtractorUpdateService = null;
- connect();
+ Slog.w(TAG, "service " + serviceName + " died; reconnecting");
+ synchronized (mUpdateServiceMap) {
+ mUpdateServiceMap.remove(serviceName);
+ }
+ connect(serviceName);
}
}, 0);
} catch (Exception e) {
@@ -77,15 +84,18 @@ public class MediaUpdateService extends SystemService {
}
}
if (binder != null) {
- mMediaExtractorUpdateService = IMediaExtractorUpdateService.Stub.asInterface(binder);
+ synchronized (mUpdateServiceMap) {
+ mUpdateServiceMap.put(serviceName,
+ IMediaUpdateService.Stub.asInterface(binder));
+ }
mHandler.post(new Runnable() {
@Override
public void run() {
- packageStateChanged();
+ packageStateChanged(serviceName);
}
});
} else {
- Slog.w(TAG, EXTRACTOR_UPDATE_SERVICE_NAME + " not found.");
+ Slog.w(TAG, serviceName + " not found.");
}
}
@@ -106,13 +116,12 @@ public class MediaUpdateService extends SystemService {
// following ACTION_PACKAGE_ADDED case.
return;
}
- packageStateChanged();
- break;
+ // fall-thru
case Intent.ACTION_PACKAGE_CHANGED:
- packageStateChanged();
- break;
case Intent.ACTION_PACKAGE_ADDED:
- packageStateChanged();
+ for (String serviceName : UPDATE_SERVICE_NAME_ARRAY) {
+ packageStateChanged(serviceName);
+ }
break;
}
}
@@ -128,7 +137,7 @@ public class MediaUpdateService extends SystemService {
null /* broadcast permission */, null /* handler */);
}
- private void packageStateChanged() {
+ private void packageStateChanged(String serviceName) {
ApplicationInfo packageInfo = null;
boolean pluginsAvailable = false;
try {
@@ -144,17 +153,23 @@ public class MediaUpdateService extends SystemService {
+ " targetSdk:" + packageInfo.targetSdkVersion);
pluginsAvailable = false;
}
- loadExtractorPlugins(
+ loadPlugins(serviceName,
(packageInfo != null && pluginsAvailable) ? packageInfo.sourceDir : "");
}
- private void loadExtractorPlugins(String apkPath) {
+ private void loadPlugins(String serviceName, String apkPath) {
try {
- if (mMediaExtractorUpdateService != null) {
- mMediaExtractorUpdateService.loadPlugins(apkPath);
+ IMediaUpdateService service = null;
+ synchronized (serviceName) {
+ service = mUpdateServiceMap.get(serviceName);
+ }
+ if (service != null) {
+ service.loadPlugins(apkPath);
+ } else {
+ Slog.w(TAG, "service " + serviceName + " passed away");
}
} catch (Exception e) {
- Slog.w(TAG, "Error in loadPlugins", e);
+ Slog.w(TAG, "Error in loadPlugins for " + serviceName, e);
}
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d326c229d6de..6187583a0253 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -696,7 +696,7 @@ abstract public class ManagedServices {
for (int i = 0; i < userIds.size(); i++) {
final int userId = userIds.get(i);
if (enabled) {
- if (isPackageOrComponentAllowed(component.toString(), userId)
+ if (isPackageOrComponentAllowed(component.flattenToString(), userId)
|| isPackageOrComponentAllowed(component.getPackageName(), userId)) {
registerServiceLocked(component, userId);
} else {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f9d49d7ce0d1..506cc441c868 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4282,14 +4282,16 @@ public class NotificationManagerService extends SystemService {
}
private void doChannelWarningToast(CharSequence toastText) {
- final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
- final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
- if (warningEnabled) {
- Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
- Toast.LENGTH_SHORT);
- toast.show();
- }
+ Binder.withCleanCallingIdentity(() -> {
+ final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
+ final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
+ if (warningEnabled) {
+ Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 5f082572db58..9c1ac346ce32 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -16,18 +16,15 @@
package com.android.server.os;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.Build;
import android.os.IDeviceIdentifiersPolicyService;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.os.UserHandle;
+
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.server.SystemService;
/**
@@ -54,15 +51,22 @@ public final class DeviceIdentifiersPolicyService extends SystemService {
@Override
public @Nullable String getSerial() throws RemoteException {
- if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
- && mContext.checkCallingOrSelfPermission(
- Manifest.permission.READ_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED
- && mContext.checkCallingOrSelfPermission(
- Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("getSerial requires READ_PHONE_STATE"
- + " or READ_PRIVILEGED_PHONE_STATE permission");
+ // Since this invocation is on the server side a null value is used for the
+ // callingPackage as the server's package name (typically android) should not be used
+ // for any device / profile owner checks. The majority of requests for the serial number
+ // should use the getSerialForPackage method with the calling package specified.
+ if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
+ /* callingPackage */ null, "getSerial")) {
+ return Build.UNKNOWN;
+ }
+ return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+ }
+
+ @Override
+ public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException {
+ if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
+ callingPackage, "getSerial")) {
+ return Build.UNKNOWN;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 93230401eb20..a08c189cb125 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AppDetailsActivity;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -65,7 +66,9 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
/**
@@ -74,6 +77,7 @@ import java.util.List;
*/
public class LauncherAppsService extends SystemService {
+ private static final boolean SHOW_HIDDEN_APP_ENABLED = false;
private final LauncherAppsImpl mLauncherAppsImpl;
public LauncherAppsService(Context context) {
@@ -281,15 +285,84 @@ public class LauncherAppsService extends SystemService {
}
}
+ private ResolveInfo getHiddenAppActivityInfo(String packageName, int callingUid,
+ UserHandle user) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(packageName, AppDetailsActivity.class.getName()));
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
+ List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid, user.getIdentifier());
+ if (apps.size() > 0) {
+ return apps.get(0);
+ }
+ return null;
+ }
+
@Override
public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
- String packageName, UserHandle user)
- throws RemoteException {
- return queryActivitiesForUser(callingPackage,
+ String packageName, UserHandle user) throws RemoteException {
+ ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
+ callingPackage,
new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(packageName),
user);
+ if (!SHOW_HIDDEN_APP_ENABLED) {
+ return launcherActivities;
+ }
+
+ final int callingUid = injectBinderCallingUid();
+ final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
+ if (packageName != null) {
+ // If target package has launcher activities, then return those launcher
+ // activities. Otherwise, return hidden activity that forwards user to app
+ // details page.
+ if (result.size() > 0) {
+ return launcherActivities;
+ }
+ ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
+ if (info != null) {
+ result.add(info);
+ }
+ return new ParceledListSlice<>(result);
+ }
+
+ long ident = injectClearCallingIdentity();
+ try {
+ final HashSet<String> visiblePackages = new HashSet<>();
+ for (ResolveInfo info : result) {
+ visiblePackages.add(info.activityInfo.packageName);
+ }
+ final PackageManagerInternal pmInt =
+ LocalServices.getService(PackageManagerInternal.class);
+ List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0,
+ user.getIdentifier(), callingUid);
+ for (ApplicationInfo applicationInfo : installedPackages) {
+ if (!visiblePackages.contains(applicationInfo.packageName)) {
+ if (!shouldShowHiddenApp(applicationInfo)) {
+ continue;
+ }
+ ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
+ callingUid, user);
+ if (info != null) {
+ result.add(info);
+ }
+ }
+ }
+ return new ParceledListSlice<>(result);
+ } finally {
+ injectRestoreCallingIdentity(ident);
+ }
+ }
+
+ private static boolean shouldShowHiddenApp(ApplicationInfo appInfo) {
+ if (appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
+ return false;
+ }
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 329b1da82608..1180af87ae34 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -121,6 +121,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.AppDetailsActivity;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.ResourcesManager;
@@ -187,6 +188,7 @@ import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
@@ -940,6 +942,7 @@ public class PackageManagerService extends IPackageManager.Stub
private UserManagerInternal mUserManagerInternal;
private ActivityManagerInternal mActivityManagerInternal;
private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+ private StorageManagerInternal mStorageManagerInternal;
private DeviceIdleController.LocalService mDeviceIdleController;
@@ -2919,7 +2922,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
final PermissionManager.SplitPermissionInfo splitPerm =
splitPermissions.get(splitPermNum);
- final String rootPerm = splitPerm.getRootPermission();
+ final String rootPerm = splitPerm.getSplitPermission();
if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
continue;
@@ -2941,11 +2944,11 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
- final String[] newPerms = splitPerm.getNewPermissions();
+ final List<String> newPerms = splitPerm.getNewPermissions();
- final int numNewPerms = newPerms.length;
+ final int numNewPerms = newPerms.size();
for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
- final String newPerm = newPerms[newPermNum];
+ final String newPerm = newPerms.get(newPermNum);
if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
continue;
}
@@ -4598,6 +4601,13 @@ public class PackageManagerService extends IPackageManager.Stub
return mDeviceIdleController;
}
+ private StorageManagerInternal getStorageManagerInternal() {
+ if (mStorageManagerInternal == null) {
+ mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
+ }
+ return mStorageManagerInternal;
+ }
+
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
@@ -7861,10 +7871,16 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
final int callingUid = Binder.getCallingUid();
+ return new ParceledListSlice<>(
+ getInstalledApplicationsListInternal(flags, userId, callingUid));
+ }
+
+ private List<ApplicationInfo> getInstalledApplicationsListInternal(int flags, int userId,
+ int callingUid) {
if (getInstantAppPackageName(callingUid) != null) {
- return ParceledListSlice.emptyList();
+ return Collections.emptyList();
}
- if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForApplication(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
@@ -7929,7 +7945,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- return new ParceledListSlice<>(list);
+ return list;
}
}
@@ -9505,6 +9521,30 @@ public class PackageManagerService extends IPackageManager.Stub
} catch (InstallerException e) {
Slog.w(TAG, String.valueOf(e));
}
+ // If this package doesn't have a sharedUserId or there are no other packages
+ // present with same sharedUserId, then delete the sandbox data too.
+ try {
+ final SharedUserSetting sharedUserSetting = mSettings.getSharedUserLPw(
+ pkg.mSharedUserId, 0 /* pkgFlags */,
+ 0 /* pkgPrivateFlags */, false /* create */);
+ boolean deleteSandboxData = true;
+ if (sharedUserSetting != null && sharedUserSetting.packages != null) {
+ for (int i = sharedUserSetting.packages.size() - 1; i >= 0; --i) {
+ final PackageSetting packageSetting = sharedUserSetting.packages.valueAt(i);
+ if (!packageSetting.name.equals(pkg.packageName)
+ && packageSetting.readUserState(realUserId).isAvailable(
+ MATCH_UNINSTALLED_PACKAGES)) {
+ deleteSandboxData = false;
+ break;
+ }
+ }
+ }
+ if (deleteSandboxData) {
+ getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId);
+ }
+ } catch (PackageManagerException e) {
+ // Should not happen
+ }
mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
}
}
@@ -12118,7 +12158,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (mPackageListObservers.size() == 0) {
return;
}
- observers = (PackageListObserver[]) mPackageListObservers.toArray();
+ final PackageListObserver[] observerArray =
+ new PackageListObserver[mPackageListObservers.size()];
+ observers = mPackageListObservers.toArray(observerArray);
}
for (int i = observers.length - 1; i >= 0; --i) {
observers[i].onPackageAdded(packageName);
@@ -12138,7 +12180,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (mPackageListObservers.size() == 0) {
return;
}
- observers = (PackageListObserver[]) mPackageListObservers.toArray();
+ final PackageListObserver[] observerArray =
+ new PackageListObserver[mPackageListObservers.size()];
+ observers = mPackageListObservers.toArray(observerArray);
}
for (int i = observers.length - 1; i >= 0; --i) {
observers[i].onPackageRemoved(packageName);
@@ -12673,8 +12717,8 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
- PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage,
- String callingPackage, int userId) {
+ PersistableBundle appExtras, PersistableBundle launcherExtras,
+ SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
"setPackagesSuspendedAsUser");
@@ -12719,7 +12763,7 @@ public class PackageManagerService extends IPackageManager.Stub
unactionedPackages.add(packageName);
continue;
}
- pkgSetting.setSuspended(suspended, callingPackage, dialogMessage, appExtras,
+ pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
launcherExtras, userId);
changedPackagesList.add(packageName);
changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
@@ -17773,7 +17817,7 @@ public class PackageManagerService extends IPackageManager.Stub
false /*hidden*/,
false /*suspended*/,
null /*suspendingPackage*/,
- null /*dialogMessage*/,
+ null /*dialogInfo*/,
null /*suspendedAppExtras*/,
null /*suspendedLauncherExtras*/,
false /*instantApp*/,
@@ -19356,6 +19400,16 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException("Cannot disable a protected package: " + packageName);
}
}
+ // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
+ // app details activity
+ if (AppDetailsActivity.class.getName().equals(className)) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "Cannot disable a protected component: " + packageName);
+ return;
+ }
+ }
synchronized (mPackages) {
if (callingUid == Process.SHELL_UID
@@ -19820,9 +19874,7 @@ public class PackageManagerService extends IPackageManager.Stub
mDexManager.systemReady();
mPackageDexOptimizer.systemReady();
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- storageManagerInternal.addExternalStoragePolicy(
+ getStorageManagerInternal().addExternalStoragePolicy(
new StorageManagerInternal.ExternalStorageMountPolicy() {
@Override
public int getMountMode(int uid, String packageName) {
@@ -21215,10 +21267,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
prepareAppDataContentsLeafLIF(pkg, userId, flags);
- final StorageManagerInternal storageManagerInternal
- = LocalServices.getService(StorageManagerInternal.class);
- if (storageManagerInternal != null) {
- storageManagerInternal.mountExternalStorageForApp(
+ if (getStorageManagerInternal() != null) {
+ getStorageManagerInternal().prepareSandboxForApp(
pkg.packageName, appId, pkg.mSharedUserId, userId);
}
}
@@ -22255,6 +22305,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
+ int callingUid) {
+ return PackageManagerService.this.getInstalledApplicationsListInternal(flags, userId,
+ callingUid);
+ }
+
+
+ @Override
public boolean isPlatformSigned(String packageName) {
PackageSetting packageSetting = mSettings.mPackages.get(packageName);
if (packageSetting == null) {
@@ -22528,10 +22586,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public String getSuspendedDialogMessage(String suspendedPackage, int userId) {
+ public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId) {
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
- return (ps != null) ? ps.readUserState(userId).dialogMessage : null;
+ return (ps != null) ? ps.readUserState(userId).dialogInfo : null;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 93729d1949b0..e25cca43e8da 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -51,6 +51,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
@@ -1701,9 +1702,18 @@ class PackageManagerShellCommand extends ShellCommand {
}
final String callingPackage =
(Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
+
+ final SuspendDialogInfo info;
+ if (!TextUtils.isEmpty(dialogMessage)) {
+ info = new SuspendDialogInfo.Builder()
+ .setMessage(dialogMessage)
+ .build();
+ } else {
+ info = null;
+ }
try {
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
- appExtras, launcherExtras, dialogMessage, callingPackage, userId);
+ appExtras, launcherExtras, info, callingPackage, userId);
pw.println("Package " + packageName + " new suspended state: "
+ mInterface.isPackageSuspendedForUser(packageName, userId));
return 0;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index fd6aceb1ce6b..3c22f07ad108 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.Signature;
+import android.content.pm.SuspendDialogInfo;
import android.os.PersistableBundle;
import android.service.pm.PackageProto;
import android.util.ArraySet;
@@ -395,12 +396,12 @@ public abstract class PackageSettingBase extends SettingBase {
return readUserState(userId).suspended;
}
- void setSuspended(boolean suspended, String suspendingPackage, String dialogMessage,
+ void setSuspended(boolean suspended, String suspendingPackage, SuspendDialogInfo dialogInfo,
PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
final PackageUserState existingUserState = modifyUserState(userId);
existingUserState.suspended = suspended;
existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
- existingUserState.dialogMessage = suspended ? dialogMessage : null;
+ existingUserState.dialogInfo = suspended ? dialogInfo : null;
existingUserState.suspendedAppExtras = suspended ? appExtras : null;
existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
}
@@ -423,7 +424,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
- String dialogMessage, PersistableBundle suspendedAppExtras,
+ SuspendDialogInfo dialogInfo, PersistableBundle suspendedAppExtras,
PersistableBundle suspendedLauncherExtras, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
@@ -438,7 +439,7 @@ public abstract class PackageSettingBase extends SettingBase {
state.hidden = hidden;
state.suspended = suspended;
state.suspendingPackage = suspendingPackage;
- state.dialogMessage = dialogMessage;
+ state.dialogInfo = dialogInfo;
state.suspendedAppExtras = suspendedAppExtras;
state.suspendedLauncherExtras = suspendedLauncherExtras;
state.lastDisableAppCaller = lastDisableAppCaller;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 5c88e0637092..6a7e65400fa7 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -49,6 +49,7 @@ import android.content.pm.PackageUserState;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
@@ -203,6 +204,7 @@ public final class Settings {
private static final String TAG_DEFAULT_BROWSER = "default-browser";
private static final String TAG_DEFAULT_DIALER = "default-dialer";
private static final String TAG_VERSION = "version";
+ private static final String TAG_SUSPENDED_DIALOG_INFO = "suspended-dialog-info";
private static final String TAG_SUSPENDED_APP_EXTRAS = "suspended-app-extras";
private static final String TAG_SUSPENDED_LAUNCHER_EXTRAS = "suspended-launcher-extras";
@@ -222,6 +224,10 @@ public final class Settings {
private static final String ATTR_HIDDEN = "hidden";
private static final String ATTR_SUSPENDED = "suspended";
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
+ /**
+ * @deprecated Legacy attribute, kept only for upgrading from P builds.
+ */
+ @Deprecated
private static final String ATTR_SUSPEND_DIALOG_MESSAGE = "suspend_dialog_message";
// Legacy, uninstall blocks are stored separately.
@Deprecated
@@ -730,7 +736,7 @@ public final class Settings {
false /*hidden*/,
false /*suspended*/,
null /*suspendingPackage*/,
- null /*dialogMessage*/,
+ null /*dialogInfo*/,
null /*suspendedAppExtras*/,
null /*suspendedLauncherExtras*/,
instantApp,
@@ -1620,7 +1626,7 @@ public final class Settings {
false /*hidden*/,
false /*suspended*/,
null /*suspendingPackage*/,
- null /*dialogMessage*/,
+ null /*dialogInfo*/,
null /*suspendedAppExtras*/,
null /*suspendedLauncherExtras*/,
false /*instantApp*/,
@@ -1730,6 +1736,7 @@ public final class Settings {
ArraySet<String> disabledComponents = null;
PersistableBundle suspendedAppExtras = null;
PersistableBundle suspendedLauncherExtras = null;
+ SuspendDialogInfo suspendDialogInfo = null;
int packageDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1752,20 +1759,28 @@ public final class Settings {
case TAG_SUSPENDED_LAUNCHER_EXTRAS:
suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser);
break;
+ case TAG_SUSPENDED_DIALOG_INFO:
+ suspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
+ break;
default:
Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
+ TAG_PACKAGE);
}
}
+ if (suspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) {
+ suspendDialogInfo = new SuspendDialogInfo.Builder()
+ .setMessage(dialogMessage)
+ .build();
+ }
if (blockUninstall) {
setBlockUninstallLPw(userId, name, true);
}
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
- hidden, suspended, suspendingPackage, dialogMessage, suspendedAppExtras,
- suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
- enabledComponents, disabledComponents, verifState, linkGeneration,
- installReason, harmfulAppWarning);
+ hidden, suspended, suspendingPackage, suspendDialogInfo,
+ suspendedAppExtras, suspendedLauncherExtras, instantApp, virtualPreload,
+ enabledCaller, enabledComponents, disabledComponents, verifState,
+ linkGeneration, installReason, harmfulAppWarning);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -2076,9 +2091,10 @@ public final class Settings {
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
ustate.suspendingPackage);
}
- if (ustate.dialogMessage != null) {
- serializer.attribute(null, ATTR_SUSPEND_DIALOG_MESSAGE,
- ustate.dialogMessage);
+ if (ustate.dialogInfo != null) {
+ serializer.startTag(null, TAG_SUSPENDED_DIALOG_INFO);
+ ustate.dialogInfo.saveToXml(serializer);
+ serializer.endTag(null, TAG_SUSPENDED_DIALOG_INFO);
}
if (ustate.suspendedAppExtras != null) {
serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
@@ -4737,8 +4753,8 @@ public final class Settings {
final PackageUserState pus = ps.readUserState(user.id);
pw.print(" suspendingPackage=");
pw.print(pus.suspendingPackage);
- pw.print(" dialogMessage=");
- pw.print(pus.dialogMessage);
+ pw.print(" dialogInfo=");
+ pw.print(pus.dialogInfo);
}
pw.print(" stopped=");
pw.print(ps.getStopped(user.id));
diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
index ad5255904d20..c93af2a5ba41 100644
--- a/services/core/java/com/android/server/pm/dex/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
@@ -1,19 +1,12 @@
{
"presubmit": [
{
- "name": "DexLoggerTests"
- },
- {
- "name": "DexManagerTests"
- },
- {
- "name": "DexoptOptionsTests"
- },
- {
- "name": "DexoptUtilsTest"
- },
- {
- "name": "PackageDexUsageTests"
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm.dex"
+ }
+ ]
},
{
"name": "DexLoggerIntegrationTests"
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6f644dd70339..0a93653ede56 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1033,8 +1033,8 @@ public final class DefaultPermissionGrantPolicy {
if (applicationInfo != null
&& applicationInfo.targetSdkVersion < splitPerm.getTargetSdk()
- && permissionsWithoutSplits.contains(splitPerm.getRootPermission())) {
- Collections.addAll(permissions, splitPerm.getNewPermissions());
+ && permissionsWithoutSplits.contains(splitPerm.getSplitPermission())) {
+ permissions.addAll(splitPerm.getNewPermissions());
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 21bf488f828c..06ee935818b3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6046,6 +6046,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
+ if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_Z: {
+ if (down && event.isCtrlPressed() && event.isAltPressed()) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
+ result &= ~ACTION_PASS_TO_USER;
+ }
+ break;
+ }
+ }
+ }
+
if (useHapticFeedback) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
"Virtual Key - Press");
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 1cba1c7bed1b..a55b49fe028d 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -95,10 +95,22 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
mIsShowing = showing;
mCallback.onShowingChanged();
- try {
- mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error informing keystore of screen lock", e);
+ int retry = 2;
+ while (retry > 0) {
+ try {
+ mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+ break;
+ } catch (RemoteException e) {
+ if (retry == 2) {
+ Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
+ + " -> refreshing service token and retrying");
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+ } else {
+ Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
+ }
+ --retry;
+ }
}
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 1abaaf2412bf..6ca4f2e49d0a 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1056,6 +1056,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
e.writeLong(entry.totalLatencyMicros);
e.writeLong(entry.cpuUsageMicros);
e.writeBoolean(entry.isInteractive);
+ e.writeLong(entry.maxCpuUsageMicros);
+ e.writeLong(entry.maxLatencyMicros);
+ e.writeLong(entry.recordedDelayMessageCount);
+ e.writeLong(entry.delayMillis);
+ e.writeLong(entry.maxDelayMillis);
pulledData.add(e);
}
}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index d36ab3f09399..5ce8145fa00e 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -28,7 +28,6 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.textclassifier.ITextClassificationCallback;
import android.service.textclassifier.ITextClassifierService;
import android.service.textclassifier.ITextLinksCallback;
@@ -41,7 +40,6 @@ import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
-import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -275,6 +273,20 @@ public final class TextClassificationManagerService extends ITextClassifierServi
IndentingPrintWriter pw = new IndentingPrintWriter(fout, " ");
TextClassificationManager tcm = mContext.getSystemService(TextClassificationManager.class);
tcm.dump(pw);
+
+ pw.printPair("context", mContext); pw.println();
+ synchronized (mLock) {
+ int size = mUserStates.size();
+ pw.print("Number user states: "); pw.println(size);
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ pw.increaseIndent();
+ UserState userState = mUserStates.valueAt(i);
+ pw.print(i); pw.print(":"); userState.dump(pw); pw.println();
+ pw.decreaseIndent();
+ }
+ }
+ }
}
private static final class PendingRequest implements IBinder.DeathRecipient {
@@ -431,6 +443,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
return willBind;
}
+ private void dump(IndentingPrintWriter pw) {
+ pw.printPair("context", mContext);
+ pw.printPair("userId", mUserId);
+ synchronized (mLock) {
+ pw.printPair("binding", mBinding);
+ pw.printPair("numberRequests", mPendingRequests.size());
+ }
+ }
+
private final class TextClassifierServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e57fea31f1a8..e38e22909957 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -102,6 +102,7 @@ import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
import com.android.server.policy.WindowManagerPolicy.StartingSurface;
@@ -1741,6 +1742,30 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return boundsLayer;
}
+ /** Get position and crop region of animation. */
+ @VisibleForTesting
+ void getAnimationBounds(Point outPosition, Rect outBounds) {
+ outPosition.set(0, 0);
+ outBounds.setEmpty();
+
+ final TaskStack stack = getStack();
+ final Task task = getTask();
+ if (task != null && task.inFreeformWindowingMode()) {
+ task.getRelativePosition(outPosition);
+ } else if (stack != null) {
+ stack.getRelativePosition(outPosition);
+ }
+
+ // Always use stack bounds in order to have the ability to animate outside the task region.
+ // It also needs to be consistent when {@link #mNeedsAnimationBoundsLayer} is set that crops
+ // according to the bounds.
+ if (stack != null) {
+ stack.getBounds(outBounds);
+ }
+ // We have the relative position so the local position can be removed from bounds.
+ outBounds.offsetTo(0, 0);
+ }
+
boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
@@ -1759,14 +1784,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
if (okToAnimate()) {
final AnimationAdapter adapter;
- final TaskStack stack = getStack();
- mTmpPoint.set(0, 0);
- mTmpRect.setEmpty();
- if (stack != null) {
- stack.getRelativePosition(mTmpPoint);
- stack.getBounds(mTmpRect);
- mTmpRect.offsetTo(0, 0);
- }
+ getAnimationBounds(mTmpPoint, mTmpRect);
// Delaying animation start isn't compatible with remote animations at all.
if (mService.mAppTransition.getRemoteAnimationController() != null
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6f728fcf1f00..642f57814c61 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -92,7 +92,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -119,7 +118,6 @@ import static com.android.server.wm.WindowManagerService.logSurface;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -2065,9 +2063,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
layoutAndAssignWindowLayersIfNeeded();
}
- int taskIdFromPoint(int x, int y) {
+ /**
+ * Used to obtain task ID when user taps on coordinate (x, y) in this display, and outside
+ * current task in focus.
+ *
+ * This returns the task ID of the foremost task at (x, y) if the task is not home. Otherwise it
+ * returns -1.
+ *
+ * @param x horizontal coordinate of the tap position
+ * @param y vertical coordinate of the tap position
+ * @return the task ID if a non-home task is found; -1 if not
+ */
+ int taskForTapOutside(int x, int y) {
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+ if (stack.isActivityTypeHome()) {
+ // We skip not only home stack, but also everything behind home because user can't
+ // see them.
+ break;
+ }
final int taskId = stack.taskIdFromPoint(x, y);
if (taskId != -1) {
return taskId;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index b7e37b2fd47a..25148d15343a 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -88,7 +88,7 @@ class TaskPositioningController {
}
taskId = task.mTaskId;
} else {
- taskId = displayContent.taskIdFromPoint(x, y);
+ taskId = displayContent.taskForTapOutside(x, y);
}
}
if (taskId >= 0) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e153a1d6594e..8b1b3275362a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -45,8 +45,8 @@ import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHA
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -1928,7 +1928,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
- if ((flagChanges & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+ if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
updateNonSystemOverlayWindowsVisibilityIfNeeded(
win, win.mWinAnimator.getShown());
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8276952d8a6c..eacbda198aba 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -46,12 +46,12 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -3470,7 +3470,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* this window is visible.
*/
boolean hideNonSystemOverlayWindowsWhenVisible() {
- return (mAttrs.privateFlags & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0
+ return (mAttrs.privateFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0
&& mSession.mCanHideNonSystemOverlayWindows;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 66cf48c8ad24..4350596ee63e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -66,4 +66,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public long forceSecurityLogs() {
return 0;
}
+
+ @Override
+ public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eeb4ad32408c..913b844d8d57 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7861,6 +7861,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return getApplicationLabel(profileOwner.getPackageName(), userHandle);
}
+ @Override
+ public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+ // Allow access to the device owner.
+ ComponentName deviceOwner = getDeviceOwnerComponent(true);
+ if (deviceOwner != null && deviceOwner.getPackageName().equals(packageName)) {
+ return true;
+ }
+ // Allow access to the profile owner for the specified user.
+ ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
+ if (profileOwner != null && profileOwner.getPackageName().equals(packageName)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Canonical name for a given package.
*/
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 52b849f93553..bbc4f4441294 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -468,6 +468,12 @@ public final class SystemServer {
}
}
+ // Diagnostic to ensure that the system is in a base healthy state. Done here as a common
+ // non-zygote process.
+ if (!VMRuntime.hasBootImageSpaces()) {
+ Slog.wtf(TAG, "Runtime is not running with a boot image!");
+ }
+
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
index fc07aa1ecd17..9512f1be66ef 100644
--- a/services/net/java/android/net/ip/IpNeighborMonitor.java
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -40,7 +40,6 @@ import android.util.Log;
import com.android.internal.util.BitUtils;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.net.InetAddress;
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 9d686efcb2ab..d197d017acce 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -28,7 +28,6 @@ import android.net.TrafficStats;
import android.net.util.InterfaceParams;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.StructGroupReq;
import android.system.StructTimeval;
import android.util.Log;
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index cfcba3a84f51..40098c1532b1 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -32,7 +32,6 @@ import android.system.Os;
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 78c0be42a448..e67f8d32fb6d 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -84,7 +84,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-3.6.1-prebuilt
+ platform-robolectric-3.6.2-prebuilt
LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests
@@ -109,4 +109,4 @@ LOCAL_TEST_PACKAGE := FrameworksServicesLib
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.6.2/run_robotests.mk
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index fb57d68082a2..7a847f3284d2 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -726,6 +726,39 @@ public class KeyValueBackupTaskTest {
}
@Test
+ public void testRunTask_whenSecondAgentUnavailable_commitsFirstAgentState() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ AgentMock agentMock = setUpAgent(PACKAGE_1);
+ setUpAgent(PACKAGE_2.unavailable());
+ agentOnBackupDo(
+ agentMock,
+ (oldState, dataOutput, newState) -> {
+ writeData(dataOutput, "key", "data".getBytes());
+ writeState(newState, "newState".getBytes());
+ });
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1, PACKAGE_2);
+
+ runTask(task);
+
+ assertThat(Files.readAllBytes(getStateFile(mTransport, PACKAGE_1))).isEqualTo(
+ "newState".getBytes());
+ }
+
+ @Test
+ public void testRunTask_whenNonIncrementalAndAgentUnavailable() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1.unavailable());
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
+
+ runTask(task);
+
+ verify(mBackupManagerService).setWorkSource(null);
+ verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
+ verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ assertBackupPendingFor(PACKAGE_1);
+ }
+
+ @Test
public void testRunTask_whenBindToAgentThrowsSecurityException() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
@@ -743,6 +776,23 @@ public class KeyValueBackupTaskTest {
}
@Test
+ public void testRunTask_whenNonIncrementalAndBindToAgentThrowsSecurityException() throws Exception {
+ TransportMock transportMock = setUpInitializedTransport(mTransport);
+ setUpAgent(PACKAGE_1);
+ doThrow(SecurityException.class)
+ .when(mBackupManagerService)
+ .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt());
+ KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
+
+ runTask(task);
+
+ verify(mBackupManagerService).setWorkSource(null);
+ verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
+ verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ assertBackupPendingFor(PACKAGE_1);
+ }
+
+ @Test
public void testRunTask_whenTransportGetBackupQuotaThrows_notifiesCorrectly() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
when(transportMock.transport.getBackupQuota(PACKAGE_1.packageName, false))
diff --git a/services/tests/mockingservicestests/Android.mk b/services/tests/mockingservicestests/Android.mk
index 8c0283318419..b83a79fc232c 100644
--- a/services/tests/mockingservicestests/Android.mk
+++ b/services/tests/mockingservicestests/Android.mk
@@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
frameworks-base-testutils \
services.core \
+ services.net \
androidx-test \
mockito-target-extended-minus-junit4 \
platform-test-annotations \
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index fdd20707aabf..8afd788256c1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -41,6 +41,9 @@ import static com.android.server.DeviceIdleController.lightStateToString;
import static com.android.server.DeviceIdleController.stateToString;
import static org.junit.Assert.assertEquals;
+
+import android.net.NetworkInfo;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -50,6 +53,8 @@ import static org.mockito.ArgumentMatchers.anyString;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
+import android.net.ConnectivityManager;
+import android.content.Intent;
import android.app.IActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -83,11 +88,14 @@ public class DeviceIdleControllerTest {
private DeviceIdleController mDeviceIdleController;
private AnyMotionDetectorForTest mAnyMotionDetector;
private AppStateTrackerForTest mAppStateTracker;
+ private InjectorForTest mInjector;
private MockitoSession mMockingSession;
@Mock
private AlarmManager mAlarmManager;
@Mock
+ private ConnectivityService mConnectivityService;
+ @Mock
private DeviceIdleController.Constants mConstants;
@Mock
private IActivityManager mIActivityManager;
@@ -99,6 +107,8 @@ public class DeviceIdleControllerTest {
private PowerManager.WakeLock mWakeLock;
class InjectorForTest extends DeviceIdleController.Injector {
+ ConnectivityService connectivityService;
+ LocationManager locationManager;
InjectorForTest(Context ctx) {
super(ctx);
@@ -122,18 +132,19 @@ public class DeviceIdleControllerTest {
@Override
ConnectivityService getConnectivityService() {
- return null;
+ return connectivityService;
}
@Override
- DeviceIdleController.Constants getConstants(DeviceIdleController controller, Handler handler,
+ DeviceIdleController.Constants getConstants(DeviceIdleController controller,
+ Handler handler,
ContentResolver resolver) {
return mConstants;
}
@Override
LocationManager getLocationManager() {
- return mLocationManager;
+ return locationManager;
}
@Override
@@ -201,8 +212,8 @@ public class DeviceIdleControllerTest {
doNothing().when(mWakeLock).acquire();
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
- mDeviceIdleController = new DeviceIdleController(getContext(),
- new InjectorForTest(getContext()));
+ mInjector = new InjectorForTest(getContext());
+ mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
mDeviceIdleController.onStart();
@@ -271,6 +282,60 @@ public class DeviceIdleControllerTest {
}
@Test
+ public void testUpdateConnectivityState() {
+ // No connectivity service
+ final boolean isConnected = mDeviceIdleController.isNetworkConnected();
+ mInjector.connectivityService = null;
+ mDeviceIdleController.updateConnectivityState(null);
+ assertEquals(isConnected, mDeviceIdleController.isNetworkConnected());
+
+ // No active network info
+ mInjector.connectivityService = mConnectivityService;
+ doReturn(null).when(mConnectivityService).getActiveNetworkInfo();
+ mDeviceIdleController.updateConnectivityState(null);
+ assertFalse(mDeviceIdleController.isNetworkConnected());
+
+ // Active network info says connected.
+ final NetworkInfo ani = mock(NetworkInfo.class);
+ doReturn(ani).when(mConnectivityService).getActiveNetworkInfo();
+ doReturn(true).when(ani).isConnected();
+ mDeviceIdleController.updateConnectivityState(null);
+ assertTrue(mDeviceIdleController.isNetworkConnected());
+
+ // Active network info says not connected.
+ doReturn(false).when(ani).isConnected();
+ mDeviceIdleController.updateConnectivityState(null);
+ assertFalse(mDeviceIdleController.isNetworkConnected());
+
+ // Wrong intent passed (false).
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 3);
+ doReturn(true).when(ani).isConnected();
+ doReturn(1).when(ani).getType();
+ mDeviceIdleController.updateConnectivityState(intent);
+ // Wrong intent means we shouldn't update the connected state.
+ assertFalse(mDeviceIdleController.isNetworkConnected());
+
+ // Intent says connected.
+ doReturn(1).when(ani).getType();
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 1);
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+ mDeviceIdleController.updateConnectivityState(intent);
+ assertTrue(mDeviceIdleController.isNetworkConnected());
+
+ // Wrong intent passed (true).
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 3);
+ // Wrong intent means we shouldn't update the connected state.
+ assertTrue(mDeviceIdleController.isNetworkConnected());
+
+ // Intent says not connected.
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 1);
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+ mDeviceIdleController.updateConnectivityState(intent);
+ assertFalse(mDeviceIdleController.isNetworkConnected());
+ }
+
+ @Test
public void testStateActiveToStateInactive_ConditionsNotMet() {
mDeviceIdleController.becomeActiveLocked("testing", 0);
verifyStateConditions(STATE_ACTIVE);
@@ -409,7 +474,7 @@ public class DeviceIdleControllerTest {
@Test
public void testStepIdleStateLocked_ValidStates_NoLocationManager() {
- mDeviceIdleController.setLocationManagerForTest(null);
+ mInjector.locationManager = null;
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
// Set state to INACTIVE.
@@ -475,6 +540,7 @@ public class DeviceIdleControllerTest {
@Test
public void testStepIdleStateLocked_ValidStates_WithLocationManager_WithProviders() {
+ mInjector.locationManager = mLocationManager;
doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString());
// Make sure the controller doesn't think there's a wake-from-idle alarm coming soon.
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
@@ -510,6 +576,160 @@ public class DeviceIdleControllerTest {
}
@Test
+ public void testLightStepIdleStateLocked_InvalidStates() {
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ // stepLightIdleStateLocked doesn't handle the ACTIVE case, so the state
+ // should stay as ACTIVE.
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ }
+
+ /**
+ * Make sure stepLightIdleStateLocked doesn't change state when the state is
+ * LIGHT_STATE_OVERRIDE.
+ */
+ @Test
+ public void testLightStepIdleStateLocked_Overriden() {
+ enterLightState(LIGHT_STATE_OVERRIDE);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
+ }
+
+ @Test
+ public void testLightStepIdleStateLocked_ValidStates_NoActiveOps_NetworkConnected() {
+ setNetworkConnected(true);
+ mDeviceIdleController.setJobsActive(false);
+ mDeviceIdleController.setAlarmsActive(false);
+ mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+ // No active ops means INACTIVE should go straight to IDLE.
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ // Should just alternate between IDLE and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
+ public void testLightStepIdleStateLocked_ValidStates_ActiveOps_NetworkConnected() {
+ setNetworkConnected(true);
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+ // Active ops means INACTIVE should go to PRE_IDLE to wait.
+ mDeviceIdleController.setJobsActive(true);
+ mDeviceIdleController.setAlarmsActive(true);
+ mDeviceIdleController.setActiveIdleOpsForTest(1);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
+
+ // Even with active ops, PRE_IDLE should go to IDLE.
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ // Should just alternate between IDLE and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
+ public void testLightStepIdleStateLocked_ValidStates_NoActiveOps_NoNetworkConnected() {
+ setNetworkConnected(false);
+ mDeviceIdleController.setJobsActive(false);
+ mDeviceIdleController.setAlarmsActive(false);
+ mDeviceIdleController.setActiveIdleOpsForTest(0);
+
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+ // No active ops means INACTIVE should go straight to IDLE.
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
+ public void testLightStepIdleStateLocked_ValidStates_ActiveOps_NoNetworkConnected() {
+ setNetworkConnected(false);
+ // Set state to INACTIVE.
+ mDeviceIdleController.becomeActiveLocked("testing", 0);
+ setChargingOn(false);
+ setScreenOn(false);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+
+ // Active ops means INACTIVE should go to PRE_IDLE to wait.
+ mDeviceIdleController.setJobsActive(true);
+ mDeviceIdleController.setAlarmsActive(true);
+ mDeviceIdleController.setActiveIdleOpsForTest(1);
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_PRE_IDLE);
+
+ // Even with active ops, PRE_IDLE should go to IDLE.
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now.
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK);
+
+ mDeviceIdleController.stepLightIdleStateLocked("testing");
+ verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
+ }
+
+ @Test
public void testExitMaintenanceEarlyIfNeededLocked_deep_noActiveOps() {
mDeviceIdleController.setJobsActive(false);
mDeviceIdleController.setAlarmsActive(false);
@@ -950,6 +1170,7 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.becomeActiveLocked("testing", 0);
break;
case STATE_LOCATING:
+ mInjector.locationManager = mLocationManager;
doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(
anyString());
// Fallthrough to step loop.
@@ -964,7 +1185,6 @@ public class DeviceIdleControllerTest {
setScreenOn(false);
setChargingOn(false);
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
- //fail(stateToString(mDeviceIdleController.getState()));
int count = 0;
while (mDeviceIdleController.getState() != state) {
// Stepping through each state ensures that the proper features are turned
@@ -972,7 +1192,8 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.stepIdleStateLocked("testing");
count++;
if (count > 10) {
- fail(stateToString(mDeviceIdleController.getState()));
+ fail("Infinite loop. Check test configuration. Currently at " +
+ stateToString(mDeviceIdleController.getState()));
}
}
break;
@@ -1001,7 +1222,8 @@ public class DeviceIdleControllerTest {
count++;
if (count > 10) {
- fail(lightStateToString(mDeviceIdleController.getLightState()));
+ fail("Infinite loop. Check test configuration. Currently at " +
+ lightStateToString(mDeviceIdleController.getLightState()));
}
}
break;
@@ -1026,6 +1248,14 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.updateInteractivityLocked();
}
+ private void setNetworkConnected(boolean connected) {
+ mInjector.connectivityService = mConnectivityService;
+ final NetworkInfo ani = mock(NetworkInfo.class);
+ doReturn(connected).when(ani).isConnected();
+ doReturn(ani).when(mConnectivityService).getActiveNetworkInfo();
+ mDeviceIdleController.updateConnectivityState(null);
+ }
+
private void verifyStateConditions(int expectedState) {
int curState = mDeviceIdleController.getState();
assertEquals(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
deleted file mode 100644
index 9de64f2cf211..000000000000
--- a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
+++ /dev/null
@@ -1,144 +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.server.am;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for exercising resizing bounds due to activity options.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
- private ActivityLaunchParamsModifier mModifier;
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
- private ActivityRecord mActivity;
-
- private LaunchParams mCurrent;
- private LaunchParams mResult;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mService = createActivityTaskManagerService();
- mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
- mCurrent = new LaunchParams();
- mResult = new LaunchParams();
-
-
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
- mActivity = new ActivityBuilder(mService).setTask(mTask).build();
- }
-
-
- @Test
- public void testSkippedInvocations() throws Exception {
- // No specified activity should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // No specified activity options should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // launch bounds specified should be ignored.
- final ActivityOptions options = ActivityOptions.makeBasic();
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Non-resizeable records should be ignored
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
- assertFalse(mActivity.isResizeable());
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // make record resizeable
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- assertTrue(mActivity.isResizeable());
-
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Does not support freeform
- mService.mSupportsFreeformWindowManagement = false;
- assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- mService.mSupportsFreeformWindowManagement = true;
- options.setLaunchBounds(new Rect());
- assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-
- // Invalid bounds
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- options.setLaunchBounds(new Rect(0, 0, -1, -1));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Valid bounds should cause the positioner to be applied.
- options.setLaunchBounds(new Rect(0, 0, 100, 100));
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- }
-
- @Test
- public void testBoundsExtraction() throws Exception {
- // Make activity resizeable and enable freeform mode.
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mService.mSupportsFreeformWindowManagement = true;
-
- ActivityOptions options = ActivityOptions.makeBasic();
- final Rect proposedBounds = new Rect(20, 30, 45, 40);
- options.setLaunchBounds(proposedBounds);
-
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, proposedBounds);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index 86541b95f395..65e4fa0f4aff 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -35,6 +35,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
@@ -165,17 +166,20 @@ public class ActivityStartInterceptorTest {
public void testSuspendedPackage() {
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
final String suspendingPackage = "com.test.suspending.package";
- final String dialogMessage = "Test Message";
+ final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
+ .setMessage("Test Message")
+ .setIcon(0x11110001)
+ .build();
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
.thenReturn(suspendingPackage);
- when(mPackageManagerInternal.getSuspendedDialogMessage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(dialogMessage);
+ when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(dialogInfo);
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
// Check intent parameters
- assertEquals(dialogMessage,
- mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE));
+ assertEquals(dialogInfo,
+ mInterceptor.mIntent.getParcelableExtra(SuspendedAppActivity.EXTRA_DIALOG_INFO));
assertEquals(suspendingPackage,
mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_SUSPENDING_PACKAGE));
assertEquals(TEST_PACKAGE_NAME,
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index bac4a525b9ea..f143e3541cc0 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -37,7 +37,7 @@ import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static com.android.server.am.ActivityDisplay.POSITION_BOTTOM;
-import static com.android.server.am.ActivityManagerService.ANIMATE;
+import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -48,6 +48,7 @@ import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -206,11 +207,11 @@ public class ActivityStarterTests extends ActivityTestsBase {
prepareStarter(launchFlags);
final IApplicationThread caller = mock(IApplicationThread.class);
- // If no caller app, return {@code null} {@link ProcessRecord}.
- final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new ProcessRecord(service.mAm, mock(ApplicationInfo.class), null, 0, null);
-
- doReturn(record).when(service.mAm).getRecordForAppLocked(anyObject());
+ final WindowProcessController wpc =
+ containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
+ ? null : new WindowProcessController(
+ service, mock(ApplicationInfo.class),null, 0, -1, null, null, null);
+ doReturn(wpc).when(service).getProcessController(anyObject());
final Intent intent = new Intent();
intent.setFlags(launchFlags);
@@ -354,10 +355,12 @@ public class ActivityStarterTests extends ActivityTestsBase {
invocation -> {
throw new RuntimeException("Not stubbed");
});
- doReturn(mockPackageManager).when(mService.mAm).getPackageManagerInternalLocked();
+ doReturn(mockPackageManager).when(mService).getPackageManagerInternalLocked();
// Never review permissions
doReturn(false).when(mockPackageManager).isPermissionsReviewRequired(any(), anyInt());
+ doNothing().when(mockPackageManager).grantEphemeralAccess(
+ anyInt(), any(), anyInt(), anyInt());
final Intent intent = new Intent();
intent.addFlags(launchFlags);
@@ -510,7 +513,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
*/
@Test
public void testActivityStartsLogging_noLoggingWhenDisabled() {
- doReturn(false).when(mService.mAm).isActivityStartsLoggingEnabled();
+ doReturn(false).when(mService).isActivityStartsLoggingEnabled();
doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
@@ -528,7 +531,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
@Test
public void testActivityStartsLogging_logsWhenEnabled() {
// note: conveniently this package doesn't have any activity visible
- doReturn(true).when(mService.mAm).isActivityStartsLoggingEnabled();
+ doReturn(true).when(mService).isActivityStartsLoggingEnabled();
doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 2008861907a6..023f7758bd0a 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -162,7 +162,8 @@ public class ActivityTestsBase {
void setupActivityManagerService(
TestActivityManagerService am, TestActivityTaskManagerService atm) {
- atm.setActivityManagerService(am);
+ atm.setActivityManagerService(am, am.mHandlerThread.getLooper(), am.mIntentFirewall,
+ am.mPendingIntentController);
atm.mAmInternal = am.getLocalService();
am.mAtmInternal = atm.getLocalService();
// Makes sure the supervisor is using with the spy object.
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index f5b8f78cfd53..0d1302f78316 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -11,239 +11,1098 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.server.am;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
-import android.content.pm.ActivityInfo.WindowLayout;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.platform.test.annotations.Presubmit;
import android.view.Gravity;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.am.LaunchParamsController.LaunchParams;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Locale;
+
/**
- * Tests for exercising resizing task bounds.
+ * Tests for default task bounds.
*
* Build/Install/Run:
* atest FrameworksServicesTests:TaskLaunchParamsModifierTests
*/
-@MediumTest
+@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
+@FlakyTest(detail = "Confirm stable in post-submit before removing")
public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
- private final static int STACK_WIDTH = 100;
- private final static int STACK_HEIGHT = 200;
-
- private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
+ private ActivityRecord mActivity;
- private TaskLaunchParamsModifier mPositioner;
+ private TaskLaunchParamsModifier mTarget;
- private LaunchParamsController.LaunchParams mCurrent;
- private LaunchParamsController.LaunchParams mResult;
+ private LaunchParams mCurrent;
+ private LaunchParams mResult;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mStack.requestResize(STACK_BOUNDS);
+ setupActivityTaskManagerService();
+ mService.mSupportsFreeformWindowManagement = true;
+ when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
+
+ mActivity = new ActivityBuilder(mService).build();
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+
+ mTarget = new TaskLaunchParamsModifier(mSupervisor);
+
+ mCurrent = new LaunchParams();
+ mCurrent.reset();
+ mResult = new LaunchParams();
+ mResult.reset();
+ }
- // We must create the task after resizing to make sure it does not inherit the stack
- // dimensions on resize.
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ // =============================
+ // Display ID Related Tests
+ // =============================
+ @Test
+ public void testDefaultToPrimaryDisplay() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
- mPositioner = new TaskLaunchParamsModifier();
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
- mResult = new LaunchParamsController.LaunchParams();
- mCurrent = new LaunchParamsController.LaunchParams();
+ assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that the setup bounds are set as expected with the stack bounds set and the task
- * bounds still {@code null}.
- * @throws Exception
- */
@Test
- public void testInitialBounds() throws Exception {
- assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
- assertEquals(mTask.getOverrideBounds(), new Rect());
+ public void testUsesPreviousDisplayIdIfSet() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(display.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testLaunchNoWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
- null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
+ public void testUsesSourcesDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ ActivityRecord source = createSourceActivity(fullscreenDisplay);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, /* options */ null, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testlaunchEmptyWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
+ public void testUsesOptionsDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ ActivityRecord source = createSourceActivity(freeformDisplay);
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
- * according to specification.
- * @throws Exception
- */
+ // =====================================
+ // Launch Windowing Mode Related Tests
+ // =====================================
@Test
- public void testlaunchWindowLayoutGravity() throws Exception {
- // Unspecified gravity should be ignored
- testGravity(Gravity.NO_GRAVITY);
+ public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
- // Unsupported gravity should be ignored
- testGravity(Gravity.LEFT);
- testGravity(Gravity.RIGHT);
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
- // Test defaults for vertical gravities
- testGravity(Gravity.TOP);
- testGravity(Gravity.BOTTOM);
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
- // Test corners
- testGravity(Gravity.TOP | Gravity.LEFT);
- testGravity(Gravity.TOP | Gravity.RIGHT);
- testGravity(Gravity.BOTTOM | Gravity.LEFT);
- testGravity(Gravity.BOTTOM | Gravity.RIGHT);
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
}
- private void testGravity(int gravity) {
- try {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(gravity));
- } finally {
- mCurrent.reset();
- mResult.reset();
- }
+ @Test
+ public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithResizeableActivity() {
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesPreDApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesAppWithoutMultipleDensitySupport() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.flags = 0;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesUnresizeableApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFullscreenOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPostNApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ // ================================
+ // Launching Bounds Related Tests
+ // ===============================
+ @Test
+ public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ final Rect expected = new Rect(0, 0, 100, 100);
+ options.setLaunchBounds(expected);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(expected, mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.left);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.top);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.left);
+ assertEquals(0, mResult.mBounds.top);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1920, mResult.mBounds.right);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1080, mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1920, mResult.mBounds.right);
+ assertEquals(1080, mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidthFraction(0.0625f).setHeightFraction(0.1f).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 486, 1020, 594), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsWithResizeableActivity() {
+ final ActivityDisplay display = mSupervisor.getActivityDisplay(DEFAULT_DISPLAY);
+ display.setBounds(new Rect(0, 0, 1920, 1080));
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ 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 testDefaultSizeSmallerThanBigScreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final int resultWidth = mResult.mBounds.width();
+ final int displayWidth = freeformDisplay.getBounds().width();
+ assertTrue("Result width " + resultWidth + " is not smaller than " + displayWidth,
+ resultWidth < displayWidth);
+
+ final int resultHeight = mResult.mBounds.height();
+ final int displayHeight = freeformDisplay.getBounds().height();
+ assertTrue("Result width " + resultHeight + " is not smaller than "
+ + displayHeight, resultHeight < displayHeight);
+ }
+
+ @Test
+ public void testDefaultFreeformSizeCenteredToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertEquals("Distance to left and right should be equal.",
+ mResult.mBounds.left - displayBounds.left,
+ displayBounds.right - mResult.mBounds.right);
+ assertEquals("Distance to top and bottom should be equal.",
+ mResult.mBounds.top - displayBounds.top,
+ displayBounds.bottom - mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testCascadesToSourceSizeForFreeform() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 412, 732);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
+ assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
+ assertTrue("Bounds should be centered at somewhere in the left half, but it's "
+ + "centerX is " + mResult.mBounds.centerX(),
+ mResult.mBounds.centerX() < displayBounds.centerX());
+ assertTrue("Bounds should be centered at somewhere in the top half, but it's "
+ + "centerY is " + mResult.mBounds.centerY(),
+ mResult.mBounds.centerY() < displayBounds.centerY());
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 200, 400);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_LargerThanDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.setTo(mSupervisor.getOverrideConfiguration());
+ overrideConfig.setLayoutDirection(new Locale("ar"));
+ mSupervisor.onConfigurationChanged(overrideConfig);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
}
- /**
- * Ensures that a task which causes a conflict with another task when positioned is adjusted as
- * expected.
- * @throws Exception
- */
- @Test
- public void testLaunchWindowCenterConflict() throws Exception {
- testConflict(Gravity.NO_GRAVITY);
- testConflict(Gravity.TOP);
- testConflict(Gravity.BOTTOM);
- testConflict(Gravity.TOP | Gravity.LEFT);
- testConflict(Gravity.TOP | Gravity.RIGHT);
- testConflict(Gravity.BOTTOM | Gravity.LEFT);
- testConflict(Gravity.BOTTOM | Gravity.RIGHT);
- }
-
- private void testConflict(int gravity) {
- final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
-
- // layout first task
- mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
-
- // Second task will be laid out on top of the first so starting bounds is the same.
- final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
-
- ActivityRecord activity = null;
- TaskRecord secondTask = null;
-
- // wrap with try/finally to ensure cleanup of activity/stack.
- try {
- // empty tasks are ignored in conflicts
- activity = new ActivityBuilder(mService).setTask(mTask).build();
-
- // Create secondary task
- secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-
- // layout second task
- assertEquals(RESULT_CONTINUE,
- mPositioner.onCalculate(secondTask, layout, null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
-
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
- || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
- mStack.getOverrideBounds()), 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP
- || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
- } else {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
- TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
- }
-
- assertEquals(mResult.mBounds, expectedBounds);
- } finally {
- // Remove task and activity to prevent influencing future tests
- if (activity != null) {
- mTask.removeActivity(activity);
- }
-
- if (secondTask != null) {
- mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
- }
+ @Test
+ public void testRespectsLayoutMinDimensions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setMinWidth(500).setMinHeight(800).build();
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(500, mResult.mBounds.width());
+ assertEquals(800, mResult.mBounds.height());
+ }
+
+ @Test
+ public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(100, 100, 500, 300));
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(200, 0, 400, 400), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(50, 50, 500, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(170, 50, 620, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(1720, 50, 1850, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(1600, 50, 1730, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(0, 0, 1800, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(120, 0, 1920, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1860, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1740, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1800, 1013));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(240, 67, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 67, 1800, 1020));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1680,
+ 953), mResult.mBounds);
+ }
+
+ private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
+ final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ display.setWindowingMode(windowingMode);
+ display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080);
+ display.getConfiguration().densityDpi = DENSITY_DEFAULT;
+ return display;
+ }
+
+ private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+ }
+
+ private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ task.setBounds(bounds);
+ }
+
+ private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
+ if (expected != parentWindowingMode) {
+ assertEquals(expected, actual);
+ } else {
+ assertEquals(WINDOWING_MODE_UNDEFINED, actual);
}
}
- private Rect getDefaultBounds(int gravity) {
- final Rect bounds = new Rect();
- bounds.set(mStack.getOverrideBounds());
+ private static class WindowLayoutBuilder {
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private float mWidthFraction = -1f;
+ private float mHeightFraction = -1f;
+ private int mGravity = Gravity.NO_GRAVITY;
+ private int mMinWidth = -1;
+ private int mMinHeight = -1;
- final int verticalInset =
- TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
- final int horizontalInset =
- TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
+ private WindowLayoutBuilder setWidth(int width) {
+ mWidth = width;
+ return this;
+ }
+
+ private WindowLayoutBuilder setHeight(int height) {
+ mHeight = height;
+ return this;
+ }
- bounds.inset(horizontalInset, verticalInset);
+ private WindowLayoutBuilder setWidthFraction(float widthFraction) {
+ mWidthFraction = widthFraction;
+ return this;
+ }
+
+ private WindowLayoutBuilder setHeightFraction(float heightFraction) {
+ mHeightFraction = heightFraction;
+ return this;
+ }
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP) {
- bounds.offsetTo(0, 0);
- } else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
- } else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- bounds.offsetTo(0, verticalInset * 2);
+ private WindowLayoutBuilder setGravity(int gravity) {
+ mGravity = gravity;
+ return this;
}
- return bounds;
+ private WindowLayoutBuilder setMinWidth(int minWidth) {
+ mMinWidth = minWidth;
+ return this;
+ }
+
+ private WindowLayoutBuilder setMinHeight(int minHeight) {
+ mMinHeight = minHeight;
+ return this;
+ }
+
+ private ActivityInfo.WindowLayout build() {
+ return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction,
+ mGravity, mMinWidth, mMinHeight);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 79eba680c998..92211ec0b649 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -887,7 +887,7 @@ public class TrampolineTest {
}
@Override
- protected BackupManagerServiceInterface createBackupManagerService() {
+ protected BackupManagerService createBackupManagerService() {
mCreateServiceCallsCount++;
return sBackupManagerServiceMock;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index c3c07880f605..517b5ade44b8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -37,6 +37,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
+import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.os.BaseBundle;
import android.os.PersistableBundle;
@@ -200,13 +201,21 @@ public class PackageManagerSettingsTests {
PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
final PersistableBundle launcherExtras1 = getPersistableBundle(
PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
- ps1.setSuspended(true, "suspendingPackage1", "dialogMsg1", appExtras1, launcherExtras1, 0);
+
+ final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
+ .setIcon(0x11220001)
+ .setTitle(0x11220002)
+ .setMessage("1st message")
+ .setNeutralButtonText(0x11220003)
+ .build();
+
+ ps1.setSuspended(true, "suspendingPackage1", dialogInfo1, appExtras1, launcherExtras1, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
- ps2.setSuspended(true, "suspendingPackage2", "dialogMsg2", null, null, 0);
+ ps2.setSuspended(true, "suspendingPackage2", null, null, null, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
- ps3.setSuspended(false, "irrelevant", "irrevelant2", null, null, 0);
+ ps3.setSuspended(false, "irrelevant", dialogInfo1, null, null, 0);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
settingsUnderTest.writePackageRestrictionsLPr(0);
@@ -221,7 +230,7 @@ public class PackageManagerSettingsTests {
readUserState(0);
assertThat(readPus1.suspended, is(true));
assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
- assertThat(readPus1.dialogMessage, equalTo("dialogMsg1"));
+ assertThat(readPus1.dialogInfo, equalTo(dialogInfo1));
assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
is(true));
@@ -230,7 +239,7 @@ public class PackageManagerSettingsTests {
readUserState(0);
assertThat(readPus2.suspended, is(true));
assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
- assertThat(readPus2.dialogMessage, equalTo("dialogMsg2"));
+ assertThat(readPus2.dialogInfo, is(nullValue()));
assertThat(readPus2.suspendedAppExtras, is(nullValue()));
assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
@@ -238,7 +247,7 @@ public class PackageManagerSettingsTests {
readUserState(0);
assertThat(readPus3.suspended, is(false));
assertThat(readPus3.suspendingPackage, is(nullValue()));
- assertThat(readPus3.dialogMessage, is(nullValue()));
+ assertThat(readPus3.dialogInfo, is(nullValue()));
assertThat(readPus3.suspendedAppExtras, is(nullValue()));
assertThat(readPus3.suspendedLauncherExtras, is(nullValue()));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 4a33ca37f767..f0ed612400ed 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -23,6 +23,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import android.content.pm.PackageUserState;
+import android.content.pm.SuspendDialogInfo;
import android.os.PersistableBundle;
import android.util.ArraySet;
@@ -37,7 +38,7 @@ import org.junit.runner.RunWith;
public class PackageUserStateTest {
@Test
- public void testPackageUserState01() {
+ public void testPackageUserState01() {
final PackageUserState testUserState = new PackageUserState();
PackageUserState oldUserState;
@@ -84,7 +85,7 @@ public class PackageUserStateTest {
}
@Test
- public void testPackageUserState02() {
+ public void testPackageUserState02() {
final PackageUserState testUserState01 = new PackageUserState();
PackageUserState oldUserState;
@@ -102,7 +103,7 @@ public class PackageUserStateTest {
}
@Test
- public void testPackageUserState03() {
+ public void testPackageUserState03() {
final PackageUserState oldUserState = new PackageUserState();
// only new user state has array defined; different
@@ -138,7 +139,7 @@ public class PackageUserStateTest {
}
@Test
- public void testPackageUserState04() {
+ public void testPackageUserState04() {
final PackageUserState oldUserState = new PackageUserState();
// only new user state has array defined; different
@@ -185,15 +186,19 @@ public class PackageUserStateTest {
launcherExtras2.putString("name", "launcherExtras2");
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
- final String dialogMessage1 = "dialogMessage1";
- final String dialogMessage2 = "dialogMessage2";
+ final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
+ .setMessage("dialogMessage1")
+ .build();
+ final SuspendDialogInfo dialogInfo2 = new SuspendDialogInfo.Builder()
+ .setMessage("dialogMessage2")
+ .build();
final PackageUserState testUserState1 = new PackageUserState();
testUserState1.suspended = true;
testUserState1.suspendedAppExtras = appExtras1;
testUserState1.suspendedLauncherExtras = launcherExtras1;
testUserState1.suspendingPackage = suspendingPackage1;
- testUserState1.dialogMessage = dialogMessage1;
+ testUserState1.dialogInfo = dialogInfo1;
PackageUserState testUserState2 = new PackageUserState(testUserState1);
assertThat(testUserState1.equals(testUserState2), is(true));
@@ -209,14 +214,14 @@ public class PackageUserStateTest {
assertThat(testUserState1.equals(testUserState2), is(false));
testUserState2 = new PackageUserState(testUserState1);
- testUserState2.dialogMessage = dialogMessage2;
+ testUserState2.dialogInfo = dialogInfo2;
assertThat(testUserState1.equals(testUserState2), is(false));
testUserState2 = new PackageUserState(testUserState1);
testUserState2.suspended = testUserState1.suspended = false;
// Everything is different but irrelevant if suspended is false
testUserState2.suspendingPackage = suspendingPackage2;
- testUserState2.dialogMessage = dialogMessage2;
+ testUserState2.dialogInfo = dialogInfo2;
testUserState2.suspendedAppExtras = appExtras2;
testUserState2.suspendedLauncherExtras = launcherExtras2;
assertThat(testUserState1.equals(testUserState2), is(true));
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java
new file mode 100644
index 000000000000..7eccd6728533
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendDialogInfoTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+import android.content.pm.SuspendDialogInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SuspendDialogInfoTest {
+ private static final int VALID_TEST_RES_ID_1 = 0x11110001;
+ private static final int VALID_TEST_RES_ID_2 = 0x11110002;
+
+ private static SuspendDialogInfo.Builder createDefaultDialogBuilder() {
+ return new SuspendDialogInfo.Builder()
+ .setIcon(VALID_TEST_RES_ID_1)
+ .setTitle(VALID_TEST_RES_ID_1)
+ .setMessage(VALID_TEST_RES_ID_1)
+ .setNeutralButtonText(VALID_TEST_RES_ID_1);
+ }
+
+ @Test
+ public void equalsComparesIcons() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder();
+ final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder();
+ assertEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ // Only icon is different
+ dialogBuilder2.setIcon(VALID_TEST_RES_ID_2);
+ assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void equalsComparesTitle() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder();
+ final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder();
+ assertEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ // Only title is different
+ dialogBuilder2.setTitle(VALID_TEST_RES_ID_2);
+ assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void equalsComparesButtonText() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder();
+ final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder();
+ assertEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ // Only button text is different
+ dialogBuilder2.setNeutralButtonText(VALID_TEST_RES_ID_2);
+ assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void equalsComparesMessageIds() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = createDefaultDialogBuilder();
+ final SuspendDialogInfo.Builder dialogBuilder2 = createDefaultDialogBuilder();
+ assertEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ // Only message is different
+ dialogBuilder2.setMessage(VALID_TEST_RES_ID_2);
+ assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void equalsIgnoresMessageStringsWhenIdsSet() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = new SuspendDialogInfo.Builder()
+ .setMessage(VALID_TEST_RES_ID_1)
+ .setMessage("1st message");
+ final SuspendDialogInfo.Builder dialogBuilder2 = new SuspendDialogInfo.Builder()
+ .setMessage(VALID_TEST_RES_ID_1)
+ .setMessage("2nd message");
+ // String messages different but should get be ignored when resource ids are set
+ assertEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void equalsComparesMessageStringsWhenNoIdsSet() {
+ final SuspendDialogInfo.Builder dialogBuilder1 = new SuspendDialogInfo.Builder()
+ .setMessage("1st message");
+ final SuspendDialogInfo.Builder dialogBuilder2 = new SuspendDialogInfo.Builder()
+ .setMessage("2nd message");
+ // Both have different messages, which are not ignored as resource ids aren't set
+ assertNotEquals(dialogBuilder1.build(), dialogBuilder2.build());
+ }
+
+ @Test
+ public void messageStringClearedWhenResIdSet() {
+ final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
+ .setMessage(VALID_TEST_RES_ID_2)
+ .setMessage("Should be cleared on build")
+ .build();
+ assertNull(dialogInfo.getDialogMessage());
+ assertEquals(VALID_TEST_RES_ID_2, dialogInfo.getDialogMessageResId());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index f115b9cd0fc5..553d234adfca 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -33,6 +33,7 @@ import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
+import android.content.pm.SuspendDialogInfo;
import android.content.res.Resources;
import android.os.BaseBundle;
import android.os.Bundle;
@@ -152,7 +153,7 @@ public class SuspendPackagesTest {
}
void drainPendingBroadcasts() {
- while (pollForIntent(5) != null);
+ while (pollForIntent(5) != null) ;
}
Intent receiveIntentFromApp() {
@@ -215,15 +216,15 @@ public class SuspendPackagesTest {
}
private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras,
- String dialogMessage) {
+ SuspendDialogInfo dialogInfo) {
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
- PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogMessage);
+ PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogInfo);
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
private void unsuspendTestPackage() {
final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
- PACKAGES_TO_SUSPEND, false, null, null, null);
+ PACKAGES_TO_SUSPEND, false, null, null, (SuspendDialogInfo) null);
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
@@ -318,7 +319,8 @@ public class SuspendPackagesTest {
@Test
public void testCannotSuspendSelf() {
final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
- new String[]{mContext.getOpPackageName()}, true, null, null, null);
+ new String[]{mContext.getOpPackageName()}, true, null, null,
+ (SuspendDialogInfo) null);
assertTrue(unchangedPkgs.length == 1);
assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
}
@@ -457,7 +459,8 @@ public class SuspendPackagesTest {
mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
ACTION_REPORT_TEST_ACTIVITY_STARTED);
final String testMessage = "This is a test message to report suspension of %1$s";
- suspendTestPackage(null, null, testMessage);
+ suspendTestPackage(null, null,
+ new SuspendDialogInfo.Builder().setMessage(testMessage).build());
startTestAppActivity();
assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
assertNotNull("Given dialog message not shown", mUiDevice.wait(
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 6d31dfbb8186..7935ec168142 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
@@ -33,10 +35,12 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyInt;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Surface;
import android.view.WindowManager;
@@ -255,4 +259,30 @@ public class AppWindowTokenTests extends WindowTestsBase {
closingWindow.removeIfPossible();
assertTrue(closingWindow.mRemoved);
}
+
+ @Test
+ public void testTransitionAnimationPositionAndBounds() {
+ final Rect stackBounds = new Rect(
+ 0/* left */, 0 /* top */, 1000 /* right */, 1000 /* bottom */);
+ final Rect taskBounds = new Rect(
+ 100/* left */, 200 /* top */, 600 /* right */, 600 /* bottom */);
+ mStack.setBounds(stackBounds);
+ mTask.setBounds(taskBounds);
+
+ mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertTransitionAnimationPositionAndBounds(taskBounds.left, taskBounds.top, stackBounds);
+
+ mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ assertTransitionAnimationPositionAndBounds(stackBounds.left, stackBounds.top, stackBounds);
+ }
+
+ private void assertTransitionAnimationPositionAndBounds(int expectedX, int expectedY,
+ Rect expectedBounds) {
+ final Point outPosition = new Point();
+ final Rect outBounds = new Rect();
+ mToken.getAnimationBounds(outPosition, outBounds);
+ assertEquals(expectedX, outPosition.x);
+ assertEquals(expectedY, outPosition.y);
+ assertEquals(expectedBounds, outBounds);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 7125246b6a29..3c8b2a036c9b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -40,27 +40,25 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for the {@link DragDropController} class.
*
- * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
@Presubmit
public class DragDropControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 3000;
@@ -109,6 +107,7 @@ public class DragDropControllerTests extends WindowTestsBase {
return window;
}
+ @Override
@Before
public void setUp() throws Exception {
final UserManagerInternal userManager = mock(UserManagerInternal.class);
@@ -127,6 +126,7 @@ public class DragDropControllerTests extends WindowTestsBase {
}
}
+ @Override
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(UserManagerInternal.class);
@@ -139,25 +139,25 @@ public class DragDropControllerTests extends WindowTestsBase {
mTarget.cancelDragAndDrop(mToken);
}
latch = new CountDownLatch(1);
- mTarget.setOnClosedCallbackLocked(() -> {
- latch.countDown();
- });
+ mTarget.setOnClosedCallbackLocked(latch::countDown);
}
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ super.tearDown();
}
@Test
- public void testDragFlow() throws Exception {
+ public void testDragFlow() {
dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
}
@Test
- public void testPerformDrag_NullDataWithGrantUri() throws Exception {
+ public void testPerformDrag_NullDataWithGrantUri() {
dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
}
@Test
- public void testPerformDrag_NullDataToOtherUser() throws Exception {
+ public void testPerformDrag_NullDataToOtherUser() {
final WindowState otherUsersWindow =
createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
doReturn(otherUsersWindow).when(mDisplayContent).getTouchableWinAtPointLocked(10, 10);
diff --git a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 60025f0f03fe..ae40f7e7d235 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -334,7 +334,7 @@ public class ScreenDecorWindowTests {
final Activity activity = mInstrumentation.startActivitySync(intent, options.toBundle());
waitForIdle();
- assertEquals(displayId, activity.getDisplay().getDisplayId());
+ assertEquals(displayId, activity.getDisplayId());
return activity;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 6f4f17380e3f..33b137ef33e2 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -29,14 +29,14 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.UserManager;
-import androidx.test.InstrumentationRegistry;
-
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import java.io.File;
+import androidx.test.InstrumentationRegistry;
+
/**
* Base class for tests that use a {@link TaskSnapshotPersister}.
*/
@@ -54,9 +54,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
}
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
+
final UserManager um = UserManager.get(InstrumentationRegistry.getContext());
mTestUserId = um.getUserHandle();
mPersister = new TaskSnapshotPersister(userId -> sFilesDir);
@@ -64,9 +66,12 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase {
mPersister.start();
}
+ @Override
@After
public void tearDown() throws Exception {
cleanDirectory();
+
+ super.tearDown();
}
private void cleanDirectory() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index ea44279b46a9..0e9a63ce728b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -19,36 +19,37 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import androidx.test.filters.SmallTest;
/**
* Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
+ * atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskStackContainersTests extends WindowTestsBase {
private TaskStack mPinnedStack;
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
+
mPinnedStack = createStackControllerOnStackOnDisplay(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
// Stack should contain visible app window to be considered visible.
@@ -60,13 +61,16 @@ public class TaskStackContainersTests extends WindowTestsBase {
assertTrue(mPinnedStack.isVisible());
}
+ @Override
@After
public void tearDown() throws Exception {
mPinnedStack.removeImmediately();
+
+ super.tearDown();
}
@Test
- public void testStackPositionChildAt() throws Exception {
+ public void testStackPositionChildAt() {
// Test that always-on-top stack can't be moved to position other than top.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
final TaskStack stack2 = createTaskStackOnDisplay(mDisplayContent);
@@ -76,8 +80,8 @@ public class TaskStackContainersTests extends WindowTestsBase {
final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stack2Pos);
- assertGreaterThan(stack2Pos, stack1Pos);
+ assertThat(pinnedStackPos).isGreaterThan(stack2Pos);
+ assertThat(stack2Pos).isGreaterThan(stack1Pos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
@@ -91,7 +95,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
}
@Test
- public void testStackPositionBelowPinnedStack() throws Exception {
+ public void testStackPositionBelowPinnedStack() {
// Test that no stack can be above pinned stack.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
@@ -99,7 +103,7 @@ public class TaskStackContainersTests extends WindowTestsBase {
final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stackPos);
+ assertThat(pinnedStackPos).isGreaterThan(stackPos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 70e4ce419e0a..cf67d786056c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -48,18 +48,17 @@ import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.WindowManager;
-import androidx.test.InstrumentationRegistry;
-
import com.android.server.AttributeCache;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import java.util.HashSet;
import java.util.LinkedList;
+import androidx.test.InstrumentationRegistry;
+
/**
* Common base class for window manager unit test classes.
*
@@ -194,14 +193,6 @@ class WindowTestsBase {
}
}
- /**
- * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
- * set-up (or null).
- */
- SurfaceBuilderFactory getSurfaceBuilderFactory() {
- return null;
- }
-
private WindowState createCommonWindow(WindowState parent, int type, String name) {
synchronized (sWm.mWindowMap) {
final WindowState win = createWindow(parent, type, name);
@@ -212,16 +203,6 @@ class WindowTestsBase {
}
}
- /** Asserts that the first entry is greater than the second entry. */
- void assertGreaterThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
- }
-
- /** Asserts that the first entry is greater than the second entry. */
- void assertLessThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
- }
-
/**
* Waits until the main handler for WM has processed all messages.
*/
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 8f9fb1b7d5ec..a610e6efda8c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -32,36 +32,35 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static com.google.common.truth.Truth.assertThat;
+
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.LinkedList;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for the {@link WindowLayersController} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ * atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
*/
@SmallTest
@FlakyTest(bugId = 74078662)
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class ZOrderingTests extends WindowTestsBase {
private class LayerRecordingTransaction extends SurfaceControl.Transaction {
- HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap();
- HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap();
+ HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
+ HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
@Override
public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
@@ -86,11 +85,11 @@ public class ZOrderingTests extends WindowTestsBase {
private SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
- };
+ }
// We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
// such that we can keep track of the parents of Surfaces as they are constructed.
- private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap();
+ private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
private class HierarchyRecorder extends SurfaceControl.Builder {
SurfaceControl mPendingParent;
@@ -109,13 +108,13 @@ public class ZOrderingTests extends WindowTestsBase {
mPendingParent = null;
return sc;
}
- };
+ }
class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
public SurfaceControl.Builder make(SurfaceSession s) {
return new HierarchyRecorder(s);
}
- };
+ }
private LayerRecordingTransaction mTransaction;
@@ -136,7 +135,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
- LinkedList<SurfaceControl> p = new LinkedList();
+ LinkedList<SurfaceControl> p = new LinkedList<>();
SurfaceControl current = sc;
do {
p.addLast(current);
@@ -153,7 +152,7 @@ public class ZOrderingTests extends WindowTestsBase {
void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
- SurfaceControl right) throws Exception {
+ SurfaceControl right) {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
@@ -168,16 +167,15 @@ public class ZOrderingTests extends WindowTestsBase {
}
if (rightTop == null) { // right is the parent of left.
- assertGreaterThan(t.getLayer(leftTop), 0);
+ assertThat(t.getLayer(leftTop)).isGreaterThan(0);
} else if (leftTop == null) { // left is the parent of right.
- assertGreaterThan(0, t.getLayer(rightTop));
+ assertThat(t.getLayer(rightTop)).isLessThan(0);
} else {
- assertGreaterThan(t.getLayer(leftTop),
- t.getLayer(rightTop));
+ assertThat(t.getLayer(leftTop)).isGreaterThan(t.getLayer(rightTop));
}
}
- void assertWindowHigher(WindowState left, WindowState right) throws Exception {
+ void assertWindowHigher(WindowState left, WindowState right) {
assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
}
@@ -186,7 +184,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithNoTarget() {
sWm.mInputMethodTarget = null;
mDisplayContent.assignChildLayers(mTransaction);
@@ -203,7 +201,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
sWm.mInputMethodTarget = imeAppTarget;
@@ -222,7 +220,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
@@ -248,7 +246,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
@@ -271,7 +269,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
mDisplayContent, "imeSystemOverlayTarget",
true /* ownerCanAddInternalSystemWindow */);
@@ -298,7 +296,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForStatusBarImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForStatusBarImeTarget() {
sWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
@@ -312,7 +310,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testStackLayers() throws Exception {
+ public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
@@ -342,7 +340,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForSysUiPanels() throws Exception {
+ public void testAssignWindowLayers_ForSysUiPanels() {
final WindowState navBarPanel =
createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
final WindowState statusBarPanel =
@@ -359,7 +357,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() throws Exception {
+ public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() {
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side.
@@ -376,7 +374,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
@Test
- public void testDockedDividerPosition() throws Exception {
+ public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index 9db823c0d3f5..55c16b367fab 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -48,6 +48,7 @@ import android.support.test.runner.AndroidJUnit4;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.StyleSpan;
+import android.util.Pair;
import android.widget.RemoteViews;
import com.android.server.UiServiceTestCase;
@@ -541,5 +542,94 @@ public class NotificationTest extends UiServiceTestCase {
assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
}
+
+ @Test
+ public void testFreeformRemoteInputActionPair_noRemoteInput() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .build())
+ .build();
+ assertNull(notification.findRemoteInputActionPair(false));
+ }
+
+ @Test
+ public void testFreeformRemoteInputActionPair_hasRemoteInput() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ RemoteInput remoteInput = new RemoteInput.Builder("a").build();
+
+ Notification.Action actionWithRemoteInput =
+ new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .addRemoteInput(remoteInput)
+ .addRemoteInput(remoteInput)
+ .build();
+
+ Notification.Action actionWithoutRemoteInput =
+ new Notification.Action.Builder(icon, "TEXT 2", intent)
+ .build();
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addAction(actionWithoutRemoteInput)
+ .addAction(actionWithRemoteInput)
+ .build();
+
+ Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+ notification.findRemoteInputActionPair(false);
+
+ assertNotNull(remoteInputActionPair);
+ assertEquals(remoteInput, remoteInputActionPair.first);
+ assertEquals(actionWithRemoteInput, remoteInputActionPair.second);
+ }
+
+ @Test
+ public void testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .addRemoteInput(
+ new RemoteInput.Builder("a")
+ .setAllowFreeFormInput(false).build())
+ .build())
+ .build();
+ assertNull(notification.findRemoteInputActionPair(true));
+ }
+
+ @Test
+ public void testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput() {
+ PendingIntent intent = mock(PendingIntent.class);
+ Icon icon = mock(Icon.class);
+
+ RemoteInput remoteInput =
+ new RemoteInput.Builder("a").setAllowFreeFormInput(false).build();
+ RemoteInput freeformRemoteInput =
+ new RemoteInput.Builder("b").setAllowFreeFormInput(true).build();
+
+ Notification.Action actionWithFreeformRemoteInput =
+ new Notification.Action.Builder(icon, "TEXT 1", intent)
+ .addRemoteInput(remoteInput)
+ .addRemoteInput(freeformRemoteInput)
+ .build();
+
+ Notification.Action actionWithoutFreeformRemoteInput =
+ new Notification.Action.Builder(icon, "TEXT 2", intent)
+ .addRemoteInput(remoteInput)
+ .build();
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addAction(actionWithoutFreeformRemoteInput)
+ .addAction(actionWithFreeformRemoteInput)
+ .build();
+
+ Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+ notification.findRemoteInputActionPair(true);
+
+ assertNotNull(remoteInputActionPair);
+ assertEquals(freeformRemoteInput, remoteInputActionPair.first);
+ assertEquals(actionWithFreeformRemoteInput, remoteInputActionPair.second);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 8d6dccc627cb..9918395005b1 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -50,7 +50,6 @@ import android.hardware.usb.gadget.V1_0.Status;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
import android.os.BatteryManager;
-import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -1982,9 +1981,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
* opens the currently attached USB accessory.
*
* @param accessory accessory to be openened.
+ * @param uid Uid of the caller
*/
public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
- UsbUserSettingsManager settings) {
+ UsbUserSettingsManager settings, int uid) {
UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
if (currentAccessory == null) {
throw new IllegalArgumentException("no accessory attached");
@@ -1995,7 +1995,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
+ currentAccessory;
throw new IllegalArgumentException(error);
}
- settings.checkPermission(accessory, Binder.getCallingUid());
+ settings.checkPermission(accessory, uid);
return nativeOpenAccessory();
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 4be70af05a3f..e0f36852c867 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -230,42 +230,29 @@ public class UsbService extends IUsbManager.Stub {
}
}
- /**
- * Check if the calling user is in the same profile group as the {@link #mCurrentUserId
- * current user}.
- *
- * @return Iff the caller is in the current user's profile group
- */
- @GuardedBy("mLock")
- private boolean isCallerInCurrentUserProfileGroupLocked() {
- int userIdInt = UserHandle.getCallingUserId();
-
- long ident = clearCallingIdentity();
- try {
- return mUserManager.isSameProfileGroup(userIdInt, mCurrentUserId);
- } finally {
- restoreCallingIdentity(ident);
- }
- }
-
/* Opens the specified USB device (host mode) */
@Override
public ParcelFileDescriptor openDevice(String deviceName, String packageName) {
ParcelFileDescriptor fd = null;
if (mHostManager != null) {
- synchronized (mLock) {
- if (deviceName != null) {
- int userIdInt = UserHandle.getCallingUserId();
- boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
-
- if (isCurrentUser) {
- fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt),
- packageName, Binder.getCallingUid());
- } else {
- Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
- " as user is not active.");
+ if (deviceName != null) {
+ int uid = Binder.getCallingUid();
+ int user = UserHandle.getUserId(uid);
+
+ long ident = clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
+ fd = mHostManager.openDevice(deviceName, getSettingsForUser(user),
+ packageName, uid);
+ } else {
+ Slog.w(TAG, "Cannot open " + deviceName + " for user " + user
+ + " as user is not active.");
+ }
}
+ } finally {
+ restoreCallingIdentity(ident);
}
}
}
@@ -287,17 +274,22 @@ public class UsbService extends IUsbManager.Stub {
@Override
public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
if (mDeviceManager != null) {
- int userIdInt = UserHandle.getCallingUserId();
-
- synchronized (mLock) {
- boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
-
- if (isCurrentUser) {
- return mDeviceManager.openAccessory(accessory, getSettingsForUser(userIdInt));
- } else {
- Slog.w(TAG, "Cannot open " + accessory + " for user " + userIdInt +
- " as user is not active.");
+ int uid = Binder.getCallingUid();
+ int user = UserHandle.getUserId(uid);
+
+ long ident = clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
+ return mDeviceManager.openAccessory(accessory, getSettingsForUser(user),
+ uid);
+ } else {
+ Slog.w(TAG, "Cannot open " + accessory + " for user " + user
+ + " as user is not active.");
+ }
}
+ } finally {
+ restoreCallingIdentity(ident);
}
}
diff --git a/startop/tools/view_compiler/Android.bp b/startop/tools/view_compiler/Android.bp
index c3e91849e636..3681529643bc 100644
--- a/startop/tools/view_compiler/Android.bp
+++ b/startop/tools/view_compiler/Android.bp
@@ -14,19 +14,30 @@
// limitations under the License.
//
+cc_defaults {
+ name: "viewcompiler_defaults",
+ shared_libs: [
+ "libdexfile",
+ "slicer",
+ ],
+}
+
cc_library_host_static {
name: "libviewcompiler",
+ defaults: ["viewcompiler_defaults"],
srcs: [
+ "dex_builder.cc",
"java_lang_builder.cc",
"util.cc",
],
static_libs: [
- "libbase"
- ]
+ "libbase",
+ ],
}
cc_binary_host {
name: "viewcompiler",
+ defaults: ["viewcompiler_defaults"],
srcs: [
"main.cc",
],
@@ -40,10 +51,12 @@ cc_binary_host {
cc_test_host {
name: "view-compiler-tests",
+ defaults: ["viewcompiler_defaults"],
srcs: [
+ "dex_builder_test.cc",
"util_test.cc",
],
static_libs: [
"libviewcompiler",
- ]
+ ],
}
diff --git a/startop/tools/view_compiler/dex_builder.cc b/startop/tools/view_compiler/dex_builder.cc
new file mode 100644
index 000000000000..7a9f41fd8f38
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.cc
@@ -0,0 +1,214 @@
+/*
+ * 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 "dex_builder.h"
+
+#include "dex/descriptors_names.h"
+#include "dex/dex_instruction.h"
+
+#include <fstream>
+#include <memory>
+
+namespace startop {
+namespace dex {
+
+using std::shared_ptr;
+using std::string;
+
+using art::Instruction;
+using ::dex::kAccPublic;
+
+const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
+const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
+
+namespace {
+// From https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic
+constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00};
+
+// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
+constexpr size_t kMaxEncodedStringLength{5};
+
+} // namespace
+
+void* TrackingAllocator::Allocate(size_t size) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
+ void* raw_buffer = buffer.get();
+ allocations_[raw_buffer] = std::move(buffer);
+ return raw_buffer;
+}
+
+void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
+
+// Write out a DEX file that is basically:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo() { return 5; }
+// }
+void WriteTestDexFile(const string& filename) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
+ cbuilder.set_source_file("dextest.java");
+
+ MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+
+ MethodBuilder::Register r = method.MakeRegister();
+ method.BuildConst4(r, 5);
+ method.BuildReturn(r);
+
+ method.Encode();
+
+ slicer::MemView image{dex_file.CreateImage()};
+
+ std::ofstream out_file(filename);
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
+ dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
+}
+
+slicer::MemView DexBuilder::CreateImage() {
+ ::dex::Writer writer(dex_file_);
+ size_t image_size{0};
+ ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
+ return slicer::MemView{image, image_size};
+}
+
+ir::String* DexBuilder::GetOrAddString(const std::string& string) {
+ ir::String*& entry = strings_[string];
+
+ if (entry == nullptr) {
+ // Need to encode the length and then write out the bytes, including 1 byte for null terminator
+ auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
+ uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
+
+ size_t header_length =
+ reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
+
+ auto end = std::copy(string.begin(), string.end(), string_data_start);
+ *end = '\0';
+
+ entry = Alloc<ir::String>();
+ // +1 for null terminator
+ entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
+ string_data_.push_back(std::move(buffer));
+ }
+ return entry;
+}
+
+ClassBuilder DexBuilder::MakeClass(const std::string& name) {
+ auto* class_def = Alloc<ir::Class>();
+ ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
+ type_def->class_def = class_def;
+
+ class_def->type = type_def;
+ class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
+ class_def->access_flags = kAccPublic;
+ return ClassBuilder{this, class_def};
+}
+
+// TODO(eholk): we probably want GetOrAddString() also
+ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
+ if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
+ return types_by_descriptor_[descriptor];
+ }
+
+ ir::Type* type = Alloc<ir::Type>();
+ type->descriptor = GetOrAddString(descriptor);
+ types_by_descriptor_[descriptor] = type;
+ return type;
+}
+
+ir::Proto* Prototype::Encode(DexBuilder* dex) const {
+ auto* proto = dex->Alloc<ir::Proto>();
+ proto->shorty = dex->GetOrAddString(Shorty());
+ proto->return_type = dex->GetOrAddType(return_type_.descriptor());
+ if (param_types_.size() > 0) {
+ proto->param_types = dex->Alloc<ir::TypeList>();
+ for (const auto& param_type : param_types_) {
+ proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
+ }
+ } else {
+ proto->param_types = nullptr;
+ }
+ return proto;
+}
+
+std::string Prototype::Shorty() const {
+ std::string shorty;
+ shorty.append(return_type_.short_descriptor());
+ for (const auto& type_descriptor : param_types_) {
+ shorty.append(type_descriptor.short_descriptor());
+ }
+ return shorty;
+}
+
+ClassBuilder::ClassBuilder(DexBuilder* parent, ir::Class* class_def)
+ : parent_(parent), class_(class_def) {}
+
+MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
+ ir::String* dex_name{parent_->GetOrAddString(name)};
+
+ auto* decl = parent_->Alloc<ir::MethodDecl>();
+ decl->name = dex_name;
+ decl->parent = class_->type;
+ decl->prototype = prototype.Encode(parent_);
+
+ return MethodBuilder{parent_, class_, decl};
+}
+
+void ClassBuilder::set_source_file(const string& source) {
+ class_->source_file = parent_->GetOrAddString(source);
+}
+
+MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
+ : dex_{dex}, class_{class_def}, decl_{decl} {}
+
+ir::EncodedMethod* MethodBuilder::Encode() {
+ auto* method = dex_->Alloc<ir::EncodedMethod>();
+ method->decl = decl_;
+
+ // TODO: make access flags configurable
+ method->access_flags = kAccPublic | ::dex::kAccStatic;
+
+ auto* code = dex_->Alloc<ir::Code>();
+ code->registers = num_registers_;
+ // TODO: support ins and outs
+ code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
+ method->code = code;
+
+ class_->direct_methods.push_back(method);
+
+ return method;
+}
+
+MethodBuilder::Register MethodBuilder::MakeRegister() { return num_registers_++; }
+
+void MethodBuilder::BuildReturn() { buffer_.push_back(Instruction::RETURN_VOID); }
+
+void MethodBuilder::BuildReturn(Register src) { buffer_.push_back(Instruction::RETURN | src << 8); }
+
+void MethodBuilder::BuildConst4(Register target, int value) {
+ DCHECK_LT(value, 16);
+ // TODO: support more registers
+ DCHECK_LT(target, 16);
+ buffer_.push_back(Instruction::CONST_4 | (value << 12) | (target << 8));
+}
+
+} // namespace dex
+} // namespace startop
diff --git a/startop/tools/view_compiler/dex_builder.h b/startop/tools/view_compiler/dex_builder.h
new file mode 100644
index 000000000000..d280abce21f5
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder.h
@@ -0,0 +1,189 @@
+/*
+ * 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 DEX_BUILDER_H_
+#define DEX_BUILDER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "slicer/dex_ir.h"
+#include "slicer/writer.h"
+
+namespace startop {
+namespace dex {
+
+// TODO: remove this once the dex generation code is complete.
+void WriteTestDexFile(const std::string& filename);
+
+//////////////////////////
+// Forward declarations //
+//////////////////////////
+class DexBuilder;
+
+// Our custom allocator for dex::Writer
+//
+// This keeps track of all allocations and ensures they are freed when
+// TrackingAllocator is destroyed. Pointers to memory allocated by this
+// allocator must not outlive the allocator.
+class TrackingAllocator : public ::dex::Writer::Allocator {
+ public:
+ virtual void* Allocate(size_t size);
+ virtual void Free(void* ptr);
+
+ private:
+ std::map<void*, std::unique_ptr<uint8_t[]>> allocations_;
+};
+
+// Represents a DEX type descriptor.
+//
+// TODO: add a way to create a descriptor for a reference of a class type.
+class TypeDescriptor {
+ public:
+ // Named constructors for base type descriptors.
+ static const TypeDescriptor Int();
+ static const TypeDescriptor Void();
+
+ // Return the full descriptor, such as I or Ljava/lang/Object
+ const std::string& descriptor() const { return descriptor_; }
+ // Return the shorty descriptor, such as I or L
+ std::string short_descriptor() const { return descriptor().substr(0, 1); }
+
+ private:
+ TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
+
+ const std::string descriptor_;
+};
+
+// Defines a function signature. For example, Prototype{TypeDescriptor::VOID, TypeDescriptor::Int}
+// represents the function type (Int) -> Void.
+class Prototype {
+ public:
+ template <typename... TypeDescriptors>
+ Prototype(TypeDescriptor return_type, TypeDescriptors... param_types)
+ : return_type_{return_type}, param_types_{param_types...} {}
+
+ // Encode this prototype into the dex file.
+ ir::Proto* Encode(DexBuilder* dex) const;
+
+ // Get the shorty descriptor, such as VII for (Int, Int) -> Void
+ std::string Shorty() const;
+
+ private:
+ const TypeDescriptor return_type_;
+ const std::vector<TypeDescriptor> param_types_;
+};
+
+// Tools to help build methods and their bodies.
+class MethodBuilder {
+ public:
+ MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl);
+
+ // Encode the method into DEX format.
+ ir::EncodedMethod* Encode();
+
+ // Registers are just represented by their number.
+ using Register = size_t;
+
+ // Create a new register to be used to storing values. Note that these are not SSA registers, like
+ // might be expected in similar code generators. This does no liveness tracking or anything, so
+ // it's up to the caller to reuse registers as appropriate.
+ Register MakeRegister();
+
+ /////////////////////////////////
+ // Instruction builder methods //
+ /////////////////////////////////
+
+ // return-void
+ void BuildReturn();
+ void BuildReturn(Register src);
+ // const/4
+ void BuildConst4(Register target, int value);
+
+ // TODO: add builders for more instructions
+
+ private:
+ DexBuilder* dex_;
+ ir::Class* class_;
+ ir::MethodDecl* decl_;
+
+ // A buffer to hold instructions we are generating.
+ std::vector<::dex::u2> buffer_;
+
+ // How many registers we've allocated
+ size_t num_registers_;
+};
+
+// A helper to build class definitions.
+class ClassBuilder {
+ public:
+ ClassBuilder(DexBuilder* parent, ir::Class* class_def);
+
+ void set_source_file(const std::string& source);
+
+ // Create a method with the given name and prototype. The returned MethodBuilder can be used to
+ // fill in the method body.
+ MethodBuilder CreateMethod(const std::string& name, Prototype prototype);
+
+ private:
+ DexBuilder* parent_;
+ ir::Class* class_;
+};
+
+// Builds Dex files from scratch.
+class DexBuilder {
+ public:
+ DexBuilder();
+
+ // Create an in-memory image of the DEX file that can either be loaded directly or written to a
+ // file.
+ slicer::MemView CreateImage();
+
+ template <typename T>
+ T* Alloc() {
+ return dex_file_->Alloc<T>();
+ }
+
+ // Find the ir::String that matches the given string, creating it if it does not exist.
+ ir::String* GetOrAddString(const std::string& string);
+ // Create a new class of the given name.
+ ClassBuilder MakeClass(const std::string& name);
+
+ // Add a type for the given descriptor, or return the existing one if it already exists.
+ // See the TypeDescriptor class for help generating these.
+ ir::Type* GetOrAddType(const std::string& descriptor);
+
+ private:
+ std::shared_ptr<ir::DexFile> dex_file_;
+
+ // allocator_ is needed to be able to encode the image.
+ TrackingAllocator allocator_;
+
+ // We'll need to allocate buffers for all of the encoded strings we create. This is where we store
+ // all of them.
+ std::vector<std::unique_ptr<uint8_t[]>> string_data_;
+
+ // Keep track of what types we've defined so we can look them up later.
+ std::map<std::string, ir::Type*> types_by_descriptor_;
+
+ // Keep track of what strings we've defined so we can look them up later.
+ std::map<std::string, ir::String*> strings_;
+};
+
+} // namespace dex
+} // namespace startop
+
+#endif // DEX_BUILDER_H_
diff --git a/startop/tools/view_compiler/dex_builder_test.cc b/startop/tools/view_compiler/dex_builder_test.cc
new file mode 100644
index 000000000000..0d8b8541caeb
--- /dev/null
+++ b/startop/tools/view_compiler/dex_builder_test.cc
@@ -0,0 +1,82 @@
+/*
+ * 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 "dex_builder.h"
+
+#include "dex/art_dex_file_loader.h"
+#include "dex/dex_file.h"
+#include "gtest/gtest.h"
+
+using namespace startop::dex;
+
+// Takes a DexBuilder, encodes it into an in-memory DEX file, verifies the resulting DEX file and
+// returns whether the verification was successful.
+bool EncodeAndVerify(DexBuilder* dex_file) {
+ slicer::MemView image{dex_file->CreateImage()};
+
+ art::ArtDexFileLoader loader;
+ std::string error_msg;
+ std::unique_ptr<const art::DexFile> loaded_dex_file{loader.Open(image.ptr<const uint8_t>(),
+ image.size(),
+ /*location=*/"",
+ /*location_checksum=*/0,
+ /*oat_dex_file=*/nullptr,
+ /*verify=*/true,
+ /*verify_checksum=*/false,
+ &error_msg)};
+ return loaded_dex_file != nullptr;
+}
+
+TEST(DexBuilderTest, VerifyDexWithClassMethod) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void()})};
+ method.BuildReturn();
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
+
+// Makes sure a bad DEX class fails to verify.
+TEST(DexBuilderTest, VerifyBadDexWithClassMethod) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ // This method has the error, because methods cannot take Void() as a parameter.
+ auto method{
+ cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Void(), TypeDescriptor::Void()})};
+ method.BuildReturn();
+ method.Encode();
+
+ EXPECT_FALSE(EncodeAndVerify(&dex_file));
+}
+
+TEST(DexBuilderTest, VerifyDexReturn5) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ auto method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int()})};
+ auto r = method.MakeRegister();
+ method.BuildConst4(r, 5);
+ method.BuildReturn(r);
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/startop/tools/view_compiler/main.cc b/startop/tools/view_compiler/main.cc
index 0ad7e24feb3b..7d791c229a98 100644
--- a/startop/tools/view_compiler/main.cc
+++ b/startop/tools/view_compiler/main.cc
@@ -16,6 +16,7 @@
#include "gflags/gflags.h"
+#include "dex_builder.h"
#include "java_lang_builder.h"
#include "util.h"
@@ -27,15 +28,17 @@
#include <string>
#include <vector>
+namespace {
+
using namespace tinyxml2;
using std::string;
constexpr char kStdoutFilename[]{"stdout"};
-DEFINE_string(package, "", "The package name for the generated class (required)");
+DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
+DEFINE_string(package, "", "The package name for the generated class (required)");
-namespace {
class ViewCompilerXmlVisitor : public XMLVisitor {
public:
ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
@@ -63,6 +66,7 @@ class ViewCompilerXmlVisitor : public XMLVisitor {
private:
JavaLangViewBuilder* builder_;
};
+
} // end namespace
int main(int argc, char** argv) {
@@ -82,6 +86,11 @@ int main(int argc, char** argv) {
return 1;
}
+ if (FLAGS_dex) {
+ startop::dex::WriteTestDexFile("test.dex");
+ return 0;
+ }
+
const char* const filename = argv[kFileNameParam];
const string layout_name = FindLayoutNameFromFilename(filename);
@@ -102,4 +111,4 @@ int main(int argc, char** argv) {
xml.Accept(&visitor);
return 0;
-} \ No newline at end of file
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 08bc9bcc4003..daa09f574651 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -397,7 +397,19 @@ public final class Call {
public static final int PROPERTY_WIFI = 0x00000008;
/**
- * Call is using high definition audio.
+ * When set, the UI should indicate to the user that a call is using high definition
+ * audio.
+ * <p>
+ * The underlying {@link ConnectionService} is responsible for reporting this
+ * property. It is important to note that this property is not intended to report the
+ * actual audio codec being used for a Call, but whether the call should be indicated
+ * to the user as high definition.
+ * <p>
+ * The Android Telephony stack reports this property for calls based on a number
+ * of factors, including which audio codec is used and whether a call is using an HD
+ * codec end-to-end. Some mobile operators choose to suppress display of an HD indication,
+ * and in these cases this property will not be set for a call even if the underlying audio
+ * codec is in fact "high definition".
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index d33a537f2194..3127b3584dd9 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -676,7 +676,7 @@ public class TelecomManager {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelecomManager from(Context context) {
return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4846092286ba..8454d12ac317 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3289,7 +3289,6 @@ public final class Telephony {
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
return values;
}
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 79298fd54c50..ac38efb4d029 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -34,8 +34,8 @@ import android.os.Parcelable;
* Received Signal Strength and Cell ID location.
*
* @deprecated This class should not be used by any app targeting
- * {@link Build.VERSION_CODES.Q Android Q} or higher. Instead callers should use
- * {@Link android.telephony.CellInfo CellInfo}.
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} or higher. Instead callers should use
+ * {@link android.telephony.CellInfo CellInfo}.
*/
@Deprecated
public class NeighboringCellInfo implements Parcelable
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index c3931557feb3..b312f8478413 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -95,6 +95,13 @@ public class NetworkRegistrationState implements Parcelable {
@RegState
private final int mRegState;
+ /**
+ * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
+ * from resource overlay or carrier config.
+ */
+ @ServiceState.RoamingType
+ private int mRoamingType;
+
private final int mAccessNetworkTechnology;
private final int mRejectCause;
@@ -140,6 +147,8 @@ public class NetworkRegistrationState implements Parcelable {
mDomain = domain;
mTransportType = transportType;
mRegState = regState;
+ mRoamingType = (regState == REG_STATE_ROAMING)
+ ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
mAccessNetworkTechnology = accessNetworkTechnology;
mRejectCause = rejectCause;
mAvailableServices = availableServices;
@@ -182,6 +191,7 @@ public class NetworkRegistrationState implements Parcelable {
mDomain = source.readInt();
mTransportType = source.readInt();
mRegState = source.readInt();
+ mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
mEmergencyOnly = source.readBoolean();
@@ -211,6 +221,31 @@ public class NetworkRegistrationState implements Parcelable {
}
/**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
+ public boolean isRoaming() {
+ return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
+ }
+
+ /**
+ * Set {@link ServiceState.RoamingType roaming type}. This could override
+ * roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public void setRoamingType(@ServiceState.RoamingType int roamingType) {
+ mRoamingType = roamingType;
+ }
+
+ /**
+ * @return {@link ServiceState.RoamingType roaming type}. This could return
+ * overridden roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public @ServiceState.RoamingType int getRoamingType() {
+ return mRoamingType;
+ }
+
+ /**
* @return Whether emergency is enabled.
*/
public boolean isEmergencyEnabled() { return mEmergencyOnly; }
@@ -280,6 +315,7 @@ public class NetworkRegistrationState implements Parcelable {
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
.append("transportType=").append(mTransportType)
.append(" regState=").append(regStateToString(mRegState))
+ .append(" roamingType=").append(mRoamingType)
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
@@ -293,9 +329,9 @@ public class NetworkRegistrationState implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegState, mAccessNetworkTechnology,
- mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity,
- mVoiceSpecificStates, mDataSpecificStates);
+ return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+ mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
+ mCellIdentity, mVoiceSpecificStates, mDataSpecificStates);
}
@Override
@@ -310,6 +346,7 @@ public class NetworkRegistrationState implements Parcelable {
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegState == other.mRegState
+ && mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
@@ -325,6 +362,7 @@ public class NetworkRegistrationState implements Parcelable {
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegState);
+ dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
dest.writeBoolean(mEmergencyOnly);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7469186a5d51..bfbcd5751bf4 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,8 @@ import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -57,7 +59,7 @@ public class ServiceState implements Parcelable {
* Normal operation condition, the phone is registered
* with an operator either in home network or in roaming.
*/
- public static final int STATE_IN_SERVICE = 0;
+ public static final int STATE_IN_SERVICE = TelephonyProtoEnums.SERVICE_STATE_IN_SERVICE; // 0
/**
* Phone is not registered with any operator, the phone
@@ -65,17 +67,19 @@ public class ServiceState implements Parcelable {
* searching to registration at all, or registration is denied, or radio
* signal is not available.
*/
- public static final int STATE_OUT_OF_SERVICE = 1;
+ public static final int STATE_OUT_OF_SERVICE =
+ TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE; // 1
/**
* The phone is registered and locked. Only emergency numbers are allowed. {@more}
*/
- public static final int STATE_EMERGENCY_ONLY = 2;
+ public static final int STATE_EMERGENCY_ONLY =
+ TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY; // 2
/**
* Radio of telephony is explicitly powered off.
*/
- public static final int STATE_POWER_OFF = 3;
+ public static final int STATE_POWER_OFF = TelephonyProtoEnums.SERVICE_STATE_POWER_OFF; // 3
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -198,6 +202,15 @@ public class ServiceState implements Parcelable {
private int mVoiceRegState = STATE_OUT_OF_SERVICE;
private int mDataRegState = STATE_OUT_OF_SERVICE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ROAMING_TYPE_" }, value = {
+ ROAMING_TYPE_NOT_ROAMING,
+ ROAMING_TYPE_UNKNOWN,
+ ROAMING_TYPE_DOMESTIC,
+ ROAMING_TYPE_INTERNATIONAL
+ })
+ public @interface RoamingType {}
/**
* Roaming type
* HOME : in home network
@@ -228,15 +241,13 @@ public class ServiceState implements Parcelable {
*/
public static final int UNKNOWN_ID = -1;
- private int mVoiceRoamingType;
- private int mDataRoamingType;
private String mVoiceOperatorAlphaLong;
private String mVoiceOperatorAlphaShort;
private String mVoiceOperatorNumeric;
private String mDataOperatorAlphaLong;
private String mDataOperatorAlphaShort;
private String mDataOperatorNumeric;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mIsManualNetworkSelection;
private boolean mIsEmergencyOnly;
@@ -246,9 +257,9 @@ public class ServiceState implements Parcelable {
@UnsupportedAppUsage
private boolean mCssIndicator;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mNetworkId;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mSystemId;
@UnsupportedAppUsage
private int mCdmaRoamingIndicator;
@@ -259,8 +270,6 @@ public class ServiceState implements Parcelable {
@UnsupportedAppUsage
private int mCdmaEriIconMode;
- private boolean mIsDataRoamingFromRegistration;
-
@UnsupportedAppUsage
private boolean mIsUsingCarrierAggregation;
@@ -332,8 +341,6 @@ public class ServiceState implements Parcelable {
protected void copyFrom(ServiceState s) {
mVoiceRegState = s.mVoiceRegState;
mDataRegState = s.mDataRegState;
- mVoiceRoamingType = s.mVoiceRoamingType;
- mDataRoamingType = s.mDataRoamingType;
mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
@@ -351,7 +358,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
@@ -367,8 +373,6 @@ public class ServiceState implements Parcelable {
public ServiceState(Parcel in) {
mVoiceRegState = in.readInt();
mDataRegState = in.readInt();
- mVoiceRoamingType = in.readInt();
- mDataRoamingType = in.readInt();
mVoiceOperatorAlphaLong = in.readString();
mVoiceOperatorAlphaShort = in.readString();
mVoiceOperatorNumeric = in.readString();
@@ -386,7 +390,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsDataRoamingFromRegistration = in.readInt() != 0;
mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationStates = new ArrayList<>();
@@ -398,8 +401,6 @@ public class ServiceState implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mVoiceRegState);
out.writeInt(mDataRegState);
- out.writeInt(mVoiceRoamingType);
- out.writeInt(mDataRoamingType);
out.writeString(mVoiceOperatorAlphaLong);
out.writeString(mVoiceOperatorAlphaShort);
out.writeString(mVoiceOperatorNumeric);
@@ -417,7 +418,6 @@ public class ServiceState implements Parcelable {
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationStates);
@@ -457,7 +457,7 @@ public class ServiceState implements Parcelable {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getVoiceRegState() {
return mVoiceRegState;
}
@@ -472,7 +472,7 @@ public class ServiceState implements Parcelable {
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getDataRegState() {
return mDataRegState;
}
@@ -533,19 +533,23 @@ public class ServiceState implements Parcelable {
* @return roaming status
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean getVoiceRoaming() {
- return mVoiceRoamingType != ROAMING_TYPE_NOT_ROAMING;
+ return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
-
/**
* Get current voice network roaming type
* @return roaming type
* @hide
*/
@UnsupportedAppUsage
- public int getVoiceRoamingType() {
- return mVoiceRoamingType;
+ public @RoamingType int getVoiceRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -553,21 +557,9 @@ public class ServiceState implements Parcelable {
* @return roaming type
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public boolean getDataRoaming() {
- return mDataRoamingType != ROAMING_TYPE_NOT_ROAMING;
- }
-
- /**
- * Set whether data network registration state is roaming
- *
- * This should only be set to the roaming value received
- * once the data registration phase has completed.
- * @hide
- */
- @UnsupportedAppUsage
- public void setDataRoamingFromRegistration(boolean dataRoaming) {
- mIsDataRoamingFromRegistration = dataRoaming;
+ return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -576,7 +568,12 @@ public class ServiceState implements Parcelable {
* @hide
*/
public boolean getDataRoamingFromRegistration() {
- return mIsDataRoamingFromRegistration;
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+ }
+ return false;
}
/**
@@ -585,8 +582,13 @@ public class ServiceState implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- public int getDataRoamingType() {
- return mDataRoamingType;
+ public @RoamingType int getDataRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -759,8 +761,6 @@ public class ServiceState implements Parcelable {
return Objects.hash(
mVoiceRegState,
mDataRegState,
- mVoiceRoamingType,
- mDataRoamingType,
mChannelNumber,
mCellBandwidths,
mVoiceOperatorAlphaLong,
@@ -780,7 +780,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsDataRoamingFromRegistration,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationStates);
@@ -794,8 +793,6 @@ public class ServiceState implements Parcelable {
return (mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
- && mVoiceRoamingType == s.mVoiceRoamingType
- && mDataRoamingType == s.mDataRoamingType
&& mChannelNumber == s.mChannelNumber
&& Arrays.equals(mCellBandwidths, s.mCellBandwidths)
&& equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
@@ -813,7 +810,6 @@ public class ServiceState implements Parcelable {
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
&& mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
s.mNetworkRegistrationStates != null &&
@@ -933,8 +929,6 @@ public class ServiceState implements Parcelable {
.append(", mChannelNumber=").append(mChannelNumber)
.append(", duplexMode()=").append(getDuplexMode())
.append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
- .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
- .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
.append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
.append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
.append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
@@ -951,7 +945,6 @@ public class ServiceState implements Parcelable {
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
.append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
@@ -962,8 +955,6 @@ public class ServiceState implements Parcelable {
if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
mVoiceRegState = state;
mDataRegState = state;
- mVoiceRoamingType = ROAMING_TYPE_NOT_ROAMING;
- mDataRoamingType = ROAMING_TYPE_NOT_ROAMING;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -983,7 +974,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsDataRoamingFromRegistration = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
mNetworkRegistrationStates = new ArrayList<>();
@@ -1029,32 +1019,50 @@ public class ServiceState implements Parcelable {
}
public void setRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
- mDataRoamingType = mVoiceRoamingType;
+ setVoiceRoaming(roaming);
+ setDataRoaming(roaming);
}
/** @hide */
@UnsupportedAppUsage
public void setVoiceRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setVoiceRoamingType(roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setVoiceRoamingType(int type) {
- mVoiceRoamingType = type;
+ public void setVoiceRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/** @hide */
@UnsupportedAppUsage
public void setDataRoaming(boolean dataRoaming) {
- mDataRoamingType = (dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setDataRoamingType(dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setDataRoamingType(int type) {
- mDataRoamingType = type;
+ public void setDataRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/**
@@ -1166,30 +1174,10 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
private void setFromNotifierBundle(Bundle m) {
- mVoiceRegState = m.getInt("voiceRegState");
- mDataRegState = m.getInt("dataRegState");
- mVoiceRoamingType = m.getInt("voiceRoamingType");
- mDataRoamingType = m.getInt("dataRoamingType");
- mVoiceOperatorAlphaLong = m.getString("operator-alpha-long");
- mVoiceOperatorAlphaShort = m.getString("operator-alpha-short");
- mVoiceOperatorNumeric = m.getString("operator-numeric");
- mDataOperatorAlphaLong = m.getString("data-operator-alpha-long");
- mDataOperatorAlphaShort = m.getString("data-operator-alpha-short");
- mDataOperatorNumeric = m.getString("data-operator-numeric");
- mIsManualNetworkSelection = m.getBoolean("manual");
- mRilVoiceRadioTechnology = m.getInt("radioTechnology");
- mRilDataRadioTechnology = m.getInt("dataRadioTechnology");
- mCssIndicator = m.getBoolean("cssIndicator");
- mNetworkId = m.getInt("networkId");
- mSystemId = m.getInt("systemId");
- mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
- mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
- mIsEmergencyOnly = m.getBoolean("emergencyOnly");
- mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
- mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
- mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
- mChannelNumber = m.getInt("ChannelNumber");
- mCellBandwidths = m.getIntArray("CellBandwidths");
+ ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE);
+ if (ssFromBundle != null) {
+ copyFrom(ssFromBundle);
+ }
}
/**
@@ -1200,10 +1188,13 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
public void fillInNotifierBundle(Bundle m) {
+ m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
+ // serviceState already consists of below entries.
+ // for backward compatibility, we continue fill in below entries.
m.putInt("voiceRegState", mVoiceRegState);
m.putInt("dataRegState", mDataRegState);
- m.putInt("voiceRoamingType", mVoiceRoamingType);
- m.putInt("dataRoamingType", mDataRoamingType);
+ m.putInt("dataRoamingType", getDataRoamingType());
+ m.putInt("voiceRoamingType", getVoiceRoamingType());
m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
m.putString("operator-numeric", mVoiceOperatorNumeric);
@@ -1219,7 +1210,7 @@ public class ServiceState implements Parcelable {
m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
- m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+ m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 96069ac98a22..40ba2b6c2355 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,12 +32,14 @@ import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.INetworkPolicyManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
@@ -86,8 +88,9 @@ public class SubscriptionManager {
/** @hide */
public static final int INVALID_PHONE_INDEX = -1;
- /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
- public static final int INVALID_SIM_SLOT_INDEX = -2;
+ /** An invalid slot identifier */
+ /** @hide */
+ public static final int INVALID_SIM_SLOT_INDEX = -1;
/** Indicates the default subscription ID in Telephony. */
public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
@@ -115,6 +118,52 @@ public class SubscriptionManager {
@UnsupportedAppUsage
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * Generates a content {@link Uri} used to receive updates on simInfo change
+ * on the given subscriptionId
+ * @param subscriptionId the subscriptionId to receive updates on
+ * @return the Uri used to observe carrier identity changes
+ * @hide
+ */
+ public static Uri getUriForSubscriptionId(int subscriptionId) {
+ return Uri.withAppendedPath(CONTENT_URI, String.valueOf(subscriptionId));
+ }
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc enabled user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
+
+ /**
+ * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "enhanced_4g");
+
+
/**
* TelephonyProvider unique key column name is the subscription id.
* <P>Type: TEXT (String)</P>
@@ -136,8 +185,9 @@ public class SubscriptionManager {
/** @hide */
public static final String SIM_SLOT_INDEX = "sim_id";
- /** Indicates SIM is not inserted. This can be returned by {@link #getSlotIndex(int)}. */
- public static final int SIM_NOT_INSERTED = -3;
+ /** SIM is not inserted */
+ /** @hide */
+ public static final int SIM_NOT_INSERTED = -1;
/**
* TelephonyProvider column name for user displayed name.
@@ -1260,22 +1310,16 @@ public class SubscriptionManager {
/**
* Get slotIndex associated with the subscription.
- *
- * @param subscriptionId the unique SubscriptionInfo index in database
- * @return slotIndex as a positive integer or a negative value,
- * <ol>
- * <li>{@link #INVALID_SUBSCRIPTION_ID} if the supplied subscriptionId is invalid </li>
- * <li>{@link #SIM_NOT_INSERTED} if sim is not inserted </li>
- * <li>{@link #INVALID_SIM_SLOT_INDEX} if the supplied subscriptionId doesn't have an
- * associated slot index </li>
- * </ol>
- */
- public static int getSlotIndex(int subscriptionId) {
- if (!isValidSubscriptionId(subscriptionId)) {
+ * @return slotIndex as a positive integer or a negative value if an error either
+ * SIM_NOT_INSERTED or < 0 if an invalid slot index
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static int getSlotIndex(int subId) {
+ if (!isValidSubscriptionId(subId)) {
if (DBG) {
- logd("[getSlotIndex]- supplied subscriptionId is invalid. ");
+ logd("[getSlotIndex]- fail");
}
- return INVALID_SUBSCRIPTION_ID;
}
int result = INVALID_SIM_SLOT_INDEX;
@@ -1283,7 +1327,7 @@ public class SubscriptionManager {
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getSlotIndex(subscriptionId);
+ result = iSub.getSlotIndex(subId);
}
} catch (RemoteException ex) {
// ignore it
@@ -1325,7 +1369,7 @@ public class SubscriptionManager {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static int getPhoneId(int subId) {
if (!isValidSubscriptionId(subId)) {
if (DBG) {
@@ -1607,7 +1651,7 @@ public class SubscriptionManager {
* Check if the subscription ID is usable.
*
* A usable subscription ID has a valid value except some special values such as
- * {@link DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
+ * {@link #DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
*
* @param subscriptionId the subscription ID
* @return {@code true} if the subscription ID is usable; {@code false} otherwise.
@@ -1621,7 +1665,7 @@ public class SubscriptionManager {
* usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static boolean isUsableSubIdValue(int subId) {
return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE;
}
@@ -1639,7 +1683,7 @@ public class SubscriptionManager {
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
int[] subIds = SubscriptionManager.getSubId(phoneId);
if (subIds != null && subIds.length > 0) {
@@ -2189,9 +2233,10 @@ public class SubscriptionManager {
* Provide all available user downloaded profiles on phone which are used only for
* opportunistic data.
* @param slotIndex slot on which the profiles are queried from.
+ * @return the list of opportunistic subscription info. If none exists, an empty list.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
+ public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
List<SubscriptionInfo> subInfoList = null;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 52c8f5a58ebe..914ff1f85c19 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,6 +60,7 @@ import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -229,7 +230,8 @@ public class TelephonyManager {
/** @hide
/* @deprecated - use getSystemService as described above */
- @UnsupportedAppUsage
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelephonyManager getDefault() {
return sInstance;
}
@@ -318,7 +320,7 @@ public class TelephonyManager {
}
/** {@hide} */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public static TelephonyManager from(Context context) {
return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
@@ -1266,15 +1268,18 @@ public class TelephonyManager {
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*
* @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
* MEID for CDMA.
*/
@Deprecated
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId() {
try {
ITelephony telephony = getITelephony();
@@ -1292,8 +1297,11 @@ public class TelephonyManager {
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*
* @param slotIndex of which deviceID is returned
*
@@ -1301,8 +1309,8 @@ public class TelephonyManager {
* MEID for CDMA.
*/
@Deprecated
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getDeviceId(int slotIndex) {
// FIXME this assumes phoneId == slotIndex
try {
@@ -1321,11 +1329,14 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei() {
return getImei(getSlotIndex());
}
@@ -1334,13 +1345,16 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*
* @param slotIndex of which IMEI is returned
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getImei(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1384,11 +1398,14 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid() {
return getMeid(getSlotIndex());
}
@@ -1396,13 +1413,16 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+ * device or profile owner. The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*
* @param slotIndex of which MEID is returned
*/
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner.
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getMeid(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -1599,8 +1619,7 @@ public class TelephonyManager {
ITelephony telephony = getITelephony();
if (telephony == null)
return null;
- return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
- mContext.getApplicationInfo().targetSdkVersion);
+ return telephony.getNeighboringCellInfo(mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1887,7 +1906,7 @@ public class TelephonyManager {
* @param subId
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getNetworkOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1915,7 +1934,7 @@ public class TelephonyManager {
* @param subId
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getNetworkOperator(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getNetworkOperatorForPhone(phoneId);
@@ -2239,7 +2258,7 @@ public class TelephonyManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getDataNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -2275,7 +2294,7 @@ public class TelephonyManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public int getVoiceNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -2428,39 +2447,46 @@ public class TelephonyManager {
*
* These are the ordinal value of IccCardConstants.State.
*/
- public static final int SIM_STATE_UNKNOWN = 0;
+
+ public static final int SIM_STATE_UNKNOWN = TelephonyProtoEnums.SIM_STATE_UNKNOWN; // 0
/** SIM card state: no SIM card is available in the device */
- public static final int SIM_STATE_ABSENT = 1;
+ public static final int SIM_STATE_ABSENT = TelephonyProtoEnums.SIM_STATE_ABSENT; // 1
/** SIM card state: Locked: requires the user's SIM PIN to unlock */
- public static final int SIM_STATE_PIN_REQUIRED = 2;
+ public static final int SIM_STATE_PIN_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PIN_REQUIRED; // 2
/** SIM card state: Locked: requires the user's SIM PUK to unlock */
- public static final int SIM_STATE_PUK_REQUIRED = 3;
+ public static final int SIM_STATE_PUK_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PUK_REQUIRED; // 3
/** SIM card state: Locked: requires a network PIN to unlock */
- public static final int SIM_STATE_NETWORK_LOCKED = 4;
+ public static final int SIM_STATE_NETWORK_LOCKED =
+ TelephonyProtoEnums.SIM_STATE_NETWORK_LOCKED; // 4
/** SIM card state: Ready */
- public static final int SIM_STATE_READY = 5;
+ public static final int SIM_STATE_READY = TelephonyProtoEnums.SIM_STATE_READY; // 5
/** SIM card state: SIM Card is NOT READY */
- public static final int SIM_STATE_NOT_READY = 6;
+ public static final int SIM_STATE_NOT_READY = TelephonyProtoEnums.SIM_STATE_NOT_READY; // 6
/** SIM card state: SIM Card Error, permanently disabled */
- public static final int SIM_STATE_PERM_DISABLED = 7;
+ public static final int SIM_STATE_PERM_DISABLED =
+ TelephonyProtoEnums.SIM_STATE_PERM_DISABLED; // 7
/** SIM card state: SIM Card Error, present but faulty */
- public static final int SIM_STATE_CARD_IO_ERROR = 8;
+ public static final int SIM_STATE_CARD_IO_ERROR =
+ TelephonyProtoEnums.SIM_STATE_CARD_IO_ERROR; // 8
/** SIM card state: SIM Card restricted, present but not usable due to
* carrier restrictions.
*/
- public static final int SIM_STATE_CARD_RESTRICTED = 9;
+ public static final int SIM_STATE_CARD_RESTRICTED =
+ TelephonyProtoEnums.SIM_STATE_CARD_RESTRICTED; // 9
/**
* SIM card state: Loaded: SIM card applications have been loaded
* @hide
*/
@SystemApi
- public static final int SIM_STATE_LOADED = 10;
+ public static final int SIM_STATE_LOADED = TelephonyProtoEnums.SIM_STATE_LOADED; // 10
/**
* SIM card state: SIM Card is present
* @hide
*/
@SystemApi
- public static final int SIM_STATE_PRESENT = 11;
+ public static final int SIM_STATE_PRESENT = TelephonyProtoEnums.SIM_STATE_PRESENT; // 11
/**
* Extra included in {@link #ACTION_SIM_CARD_STATE_CHANGED} and
@@ -2751,7 +2777,7 @@ public class TelephonyManager {
* @param subId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperator(int subId) {
return getSimOperatorNumeric(subId);
}
@@ -2765,7 +2791,7 @@ public class TelephonyManager {
* @see #getSimState
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumeric() {
int subId = mSubId;
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
@@ -2794,7 +2820,7 @@ public class TelephonyManager {
* @param subId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumeric(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNumericForPhone(phoneId);
@@ -2808,7 +2834,7 @@ public class TelephonyManager {
* @param phoneId for which SimOperator is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorNumericForPhone(int phoneId) {
return getTelephonyProperty(phoneId,
TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
@@ -2835,7 +2861,7 @@ public class TelephonyManager {
* @param subId for which SimOperatorName is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNameForPhone(phoneId);
@@ -2865,7 +2891,7 @@ public class TelephonyManager {
* @param subId for which SimCountryIso is returned
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSimCountryIso(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimCountryIsoForPhone(phoneId);
@@ -2886,11 +2912,15 @@ public class TelephonyManager {
* Returns the serial number of the SIM, if applicable. Return null if it is
* unavailable.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner, or that the calling app has carrier privileges (see {@link
+ * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSimSerialNumber() {
return getSimSerialNumber(getSubId());
}
@@ -2898,11 +2928,18 @@ public class TelephonyManager {
/**
* Returns the serial number for the given subscription, if applicable. Return null if it is
* unavailable.
- * <p>
+ *
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner, or that the calling app has carrier privileges (see {@link
+ * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
+ *
* @param subId for which Sim Serial number is returned
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@UnsupportedAppUsage
public String getSimSerialNumber(int subId) {
try {
@@ -3037,11 +3074,15 @@ public class TelephonyManager {
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
* Return null if it is unavailable.
*
- * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner, or that the calling app has carrier privileges (see {@link
+ * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getSubscriberId() {
return getSubscriberId(getSubId());
}
@@ -3051,11 +3092,18 @@ public class TelephonyManager {
* for a subscription.
* Return null if it is unavailable.
*
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+ * profile owner, or that the calling app has carrier privileges (see {@link
+ * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+ * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+ * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+ * release.
+ *
* @param subId whose subscriber id is returned
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getSubscriberId(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -3440,7 +3488,7 @@ public class TelephonyManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public String getMsisdn(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -4373,7 +4421,7 @@ public class TelephonyManager {
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
@@ -5355,7 +5403,7 @@ public class TelephonyManager {
@UnsupportedAppUsage
public static String getTelephonyProperty(String property, String defaultVal) {
String propVal = SystemProperties.get(property);
- return propVal == null ? defaultVal : propVal;
+ return TextUtils.isEmpty(propVal) ? defaultVal : propVal;
}
/** @hide */
@@ -7897,7 +7945,7 @@ public class TelephonyManager {
* either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public ServiceState getServiceStateForSubscriber(int subId) {
try {
ITelephony service = getITelephony();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8379f8cefda0..eb144f9053be 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -80,7 +80,7 @@ public class ApnSetting implements Parcelable {
*/
public static final int TYPE_ALL = ApnTypes.ALL;
/** APN type for default data traffic. */
- public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
+ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
/** APN type for MMS traffic. */
public static final int TYPE_MMS = ApnTypes.MMS;
/** APN type for SUPL assisted GPS. */
@@ -979,7 +979,7 @@ public class ApnSetting implements Parcelable {
return false;
}
// DEFAULT can handle HIPRI.
- if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+ if (hasApnType(type)) {
return true;
}
return false;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 32eb12b49cf0..1087fce21316 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -280,7 +280,7 @@ interface ITelephony {
/**
* Returns the neighboring cell information of the device.
*/
- List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg, int targetSdk);
+ List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
int getCallState();
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3a263504a2ec..cb8269efe443 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -420,6 +420,7 @@ public interface RILConstants {
int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 201;
int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 202;
int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203;
+ int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 23ea237a32eb..9730ebc57fcf 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -19,14 +19,20 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,6 +44,10 @@ public final class TelephonyPermissions {
private static final boolean DBG = false;
+ // When set to true this flag will treat all apps that fail the device identifier check as
+ // though they are targeting pre-Q and return dummy data instead of throwing a SecurityException
+ private static final boolean RELAX_DEVICE_IDENTIFIER_CHECK = true;
+
private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
@@ -135,6 +145,179 @@ public final class TelephonyPermissions {
}
/**
+ * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
+ * calling package passes a DevicePolicyManager Device Owner / Profile Owner device
+ * identifier access check,
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission. In this case the caller would expect to have access to the device
+ * identifiers so false is returned instead of throwing a SecurityException to indicate
+ * the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
+ String callingPackage, String message) {
+ return checkCallingOrSelfReadDeviceIdentifiers(context,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
+ }
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
+ * calling package passes a DevicePolicyManager Device Owner / Profile Owner device
+ * identifier access check,
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+ * or carrier privileges.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission or carrier privileges. In this case the caller would expect to have access
+ * to the device identifiers so false is returned instead of throwing a SecurityException
+ * to indicate the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
+ String callingPackage, String message) {
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
+ // if the device identifier check completes successfully then grant access.
+ if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
+ return true;
+ }
+ // else the calling package is not authorized to access the device identifiers; call
+ // a central method to report the failure based on the target SDK and if the calling package
+ // has the READ_PHONE_STATE permission or carrier privileges that were previously required
+ // to access the identifiers.
+ return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+ message);
+ }
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+ * access check, or the calling package has carrier privleges.
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission. In this case the caller would expect to have access to the device
+ * identifiers so false is returned instead of throwing a SecurityException to indicate
+ * the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
+ String callingPackage, String message) {
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
+ // if the device identifiers can be read then grant access to the subscriber identifiers
+ if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
+ return true;
+ }
+ // If the calling package has carrier privileges then allow access to the subscriber
+ // identifiers.
+ if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus(
+ TELEPHONY_SUPPLIER, subId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+ message);
+ }
+
+ /**
+ * Checks whether the app with the given pid/uid can read device identifiers.
+ *
+ * @returns true if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier access
+ * check.
+ */
+ private static boolean checkReadDeviceIdentifiers(Context context, int pid, int uid,
+ String callingPackage) {
+ // Allow system and root access to the device identifiers.
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
+ return true;
+ }
+ // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
+ if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ // if the calling package is null then return now as there's no way to perform the
+ // DevicePolicyManager device / profile owner checks.
+ if (callingPackage == null) {
+ return false;
+ }
+ // Allow access to a device / profile owner app.
+ DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccessAsUser(
+ callingPackage, Binder.getCallingUserHandle().getIdentifier())) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
+ *
+ * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission or carrier privileges.
+ * @throws SecurityException if the caller does not meet any of the requirements for the
+ * requested identifier and is targeting Q or is targeting pre-Q
+ * and does not have the READ_PHONE_STATE permission or carrier
+ * privileges.
+ */
+ private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
+ int uid, String callingPackage, String message) {
+ // if the device identifier check is relaxed then just return false to return dummy data to
+ // the caller instead of throwing a SecurityException for apps targeting Q+.
+ if (RELAX_DEVICE_IDENTIFIER_CHECK) {
+ Log.wtf(LOG_TAG,
+ "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
+ return false;
+ } else {
+ if (callingPackage != null) {
+ try {
+ // if the target SDK is pre-Q then check if the calling package would have
+ // previously had access to device identifiers.
+ ApplicationInfo callingPackageInfo =
+ context.getPackageManager().getApplicationInfo(
+ callingPackage, 0);
+ if (callingPackageInfo != null
+ && callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE,
+ pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return false;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // If the application info for the calling package could not be found then
+ // default to throwing the SecurityException.
+ }
+ }
+ throw new SecurityException(message + ": The user " + uid + " does not have the "
+ + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
+ }
+ }
+
+ /**
* Check whether the app with the given pid/uid can read the call log.
* @return {@code true} if the specified app has the read call log permission and AppOpp granted
* to it, {@code false} otherwise.
diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt
index 3bd3d68ba6cf..2b968aec1496 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -29,6 +29,7 @@ package android.test.mock {
method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
+ method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
method public void setUpdateAvailable(java.lang.String, boolean);
method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 9d260ebf7231..fa5b896ea126 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -774,6 +774,12 @@ public class MockContext extends Context {
/** @hide */
@Override
+ public int getDisplayId() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public void updateDisplay(int displayId) {
throw new UnsupportedOperationException();
}
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 4c68c8bb40c2..94294f6b062a 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -10,9 +10,5 @@ LOCAL_MODULE_TAGS := tests
LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index c225e170c377..a6c21db16846 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -7,7 +7,6 @@ LOCAL_CERTIFICATE := platform
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- conscrypt \
android.test.base \
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 750e2fb6f6b4..132135dc89bc 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -63,7 +63,8 @@ LOCAL_JNI_SHARED_LIBRARIES := \
libunwindstack \
libutilscallstack \
libziparchive \
- libz
+ libz \
+ netd_aidl_interface-cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
@@ -92,7 +93,8 @@ LOCAL_SHARED_LIBRARIES := \
liblog \
libcutils \
libnativehelper \
- libnetdaidl
+ libnetdaidl \
+ netd_aidl_interface-cpp
LOCAL_STATIC_LIBRARIES := \
libpcap \
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 37013c07ffef..adf85b0ea8e8 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -36,6 +36,7 @@
#include "cmd/Dump.h"
#include "cmd/Link.h"
#include "cmd/Optimize.h"
+#include "io/FileStream.h"
#include "util/Files.h"
#include "util/Util.h"
@@ -68,10 +69,11 @@ class VersionCommand : public Command {
/** The main entry point of AAPT. */
class MainCommand : public Command {
public:
- explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) {
+ explicit MainCommand(text::Printer* printer, IDiagnostics* diagnostics)
+ : Command("aapt2"), diagnostics_(diagnostics) {
AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
- AddOptionalSubcommand(util::make_unique<DumpCommand>(diagnostics));
+ AddOptionalSubcommand(util::make_unique<DumpCommand>(printer, diagnostics));
AddOptionalSubcommand(util::make_unique<DiffCommand>());
AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
AddOptionalSubcommand(util::make_unique<ConvertCommand>());
@@ -101,13 +103,14 @@ class MainCommand : public Command {
*/
class DaemonCommand : public Command {
public:
- explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"),
- diagnostics_(diagnostics) {
+ explicit DaemonCommand(io::FileOutputStream* out, IDiagnostics* diagnostics)
+ : Command("daemon", "m"), out_(out), diagnostics_(diagnostics) {
SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
"command. The end of an invocation is signaled by providing an empty line.");
}
int Action(const std::vector<std::string>& /* args */) override {
+ text::Printer printer(out_);
std::cout << "Ready" << std::endl;
while (true) {
@@ -132,7 +135,9 @@ class DaemonCommand : public Command {
std::vector<StringPiece> args;
args.insert(args.end(), raw_args.begin(), raw_args.end());
- if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) {
+ int result = MainCommand(&printer, diagnostics_).Execute(args, &std::cerr);
+ out_->Flush();
+ if (result != 0) {
std::cerr << "Error" << std::endl;
}
std::cerr << "Done" << std::endl;
@@ -143,6 +148,7 @@ class DaemonCommand : public Command {
}
private:
+ io::FileOutputStream* out_;
IDiagnostics* diagnostics_;
};
@@ -159,11 +165,17 @@ int MainImpl(int argc, char** argv) {
args.push_back(argv[i]);
}
- // Add the daemon subcommand here so it cannot be called while executing the daemon
+ // Use a smaller buffer so that there is less latency for printing to stdout.
+ constexpr size_t kStdOutBufferSize = 1024u;
+ aapt::io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ aapt::text::Printer printer(&fout);
+
aapt::StdErrDiagnostics diagnostics;
- auto main_command = new aapt::MainCommand(&diagnostics);
- main_command->AddOptionalSubcommand(aapt::util::make_unique<aapt::DaemonCommand>(&diagnostics));
+ auto main_command = new aapt::MainCommand(&printer, &diagnostics);
+ // Add the daemon subcommand here so it cannot be called while executing the daemon
+ main_command->AddOptionalSubcommand(
+ aapt::util::make_unique<aapt::DaemonCommand>(&fout, &diagnostics));
return main_command->Execute(args, &std::cerr);
}
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index 23ec5ab0d1f3..f1903a5a54a7 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,2 +1,3 @@
set noparent
toddke@google.com
+rtmitchell@google.com \ No newline at end of file
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index 09411b95bcfe..bdee5c9d4909 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -93,9 +93,13 @@ void Command::AddOptionalSwitch(const StringPiece& name,
flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
}
-void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand) {
+void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) {
subcommand->fullname_ = name_ + " " + subcommand->name_;
- subcommands_.push_back(std::move(subcommand));
+ if (experimental) {
+ experimental_subcommands_.push_back(std::move(subcommand));
+ } else {
+ subcommands_.push_back(std::move(subcommand));
+ }
}
void Command::SetDescription(const android::StringPiece& description) {
@@ -162,7 +166,7 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream
for (size_t i = 0; i < args.size(); i++) {
StringPiece arg = args[i];
if (*(arg.data()) != '-') {
- // Continue parsing as the sub command if the first argument matches one of the subcommands
+ // 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_) {
@@ -170,6 +174,12 @@ int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream
std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
}
}
+ for (auto& subcommand : experimental_subcommands_) {
+ if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+ return subcommand->Execute(
+ std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+ }
+ }
}
file_args.push_back(arg.to_string());
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 71dc6fe48da1..16949883d123 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -49,7 +49,7 @@ class Command {
const android::StringPiece& description, std::unordered_set<std::string>* value);
void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
bool* value);
- void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand);
+ void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
void SetDescription(const android::StringPiece& name);
@@ -83,6 +83,7 @@ class Command {
std::string fullname_;
std::vector<Flag> flags_;
std::vector<std::unique_ptr<Command>> subcommands_;
+ std::vector<std::unique_ptr<Command>> experimental_subcommands_;
};
} // namespace aapt
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 954f1ed3fb72..3ea17552ea7c 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -46,7 +46,7 @@ class IApkSerializer {
IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) = 0;
+ IArchiveWriter* writer, uint32_t compression_flags) = 0;
virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
virtual bool SerializeFile(FileReference* file, IArchiveWriter* writer) = 0;
@@ -59,7 +59,10 @@ class IApkSerializer {
bool ConvertApk(IAaptContext* context, unique_ptr<LoadedApk> apk, IApkSerializer* serializer,
IArchiveWriter* writer) {
- if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+ io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
+ if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer,
+ (manifest != nullptr && manifest->WasCompressed())
+ ? ArchiveEntry::kCompress : 0u)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return false;
@@ -133,7 +136,7 @@ class BinaryApkSerializer : public IApkSerializer {
: IApkSerializer(context, source), tableFlattenerOptions_(options) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.use_utf16 = utf16;
@@ -144,8 +147,7 @@ class BinaryApkSerializer : public IApkSerializer {
}
io::BigBufferInputStream input_stream(&buffer);
- return io::CopyInputStreamToArchive(context_, &input_stream, path, ArchiveEntry::kCompress,
- writer);
+ return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -186,7 +188,8 @@ class BinaryApkSerializer : public IApkSerializer {
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to binary XML: " << *file->path);
return false;
@@ -216,10 +219,10 @@ class ProtoApkSerializer : public IApkSerializer {
: IApkSerializer(context, source) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
pb::XmlNode pb_node;
SerializeXmlResourceToPb(*xml, &pb_node);
- return io::CopyProtoToArchive(context_, &pb_node, path, ArchiveEntry::kCompress, writer);
+ return io::CopyProtoToArchive(context_, &pb_node, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -246,7 +249,8 @@ class ProtoApkSerializer : public IApkSerializer {
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to proto XML: " << *file->path);
return false;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index d80b5ea38bbd..a23a6a46cf0f 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -125,9 +125,6 @@ class DumpContext : public IAaptContext {
} // namespace
-// Use a smaller buffer so that there is less latency for dumping to stdout.
-constexpr size_t kStdOutBufferSize = 1024u;
-
int DumpAPCCommand::Action(const std::vector<std::string>& args) {
DumpContext context;
DebugPrintTableOptions print_options;
@@ -135,41 +132,41 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
print_options.show_values = !no_values_;
if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump container specified.");
+ diag_->Error(DiagMessage() << "No dump container specified");
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
+ bool error = false;
for (auto container : args) {
io::FileInputStream input(container);
if (input.HadError()) {
context.GetDiagnostics()->Error(DiagMessage(container)
- << "failed to open file: " << input.GetError());
- return false;
+ << "failed to open file: " << input.GetError());
+ error = true;
+ continue;
}
// Try as a compiled file.
ContainerReader reader(&input);
if (reader.HadError()) {
context.GetDiagnostics()->Error(DiagMessage(container)
- << "failed to read container: " << reader.GetError());
- return false;
+ << "failed to read container: " << reader.GetError());
+ error = true;
+ continue;
}
- printer.Println("AAPT2 Container (APC)");
+ printer_->Println("AAPT2 Container (APC)");
ContainerReaderEntry* entry;
std::string error;
while ((entry = reader.Next()) != nullptr) {
if (entry->Type() == ContainerEntryType::kResTable) {
- printer.Println("kResTable");
+ printer_->Println("kResTable");
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
context.GetDiagnostics()->Error(DiagMessage(container)
- << "failed to parse proto table: "
- << entry->GetError());
+ << "failed to parse proto table: " << entry->GetError());
+ error = true;
continue;
}
@@ -177,65 +174,61 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) {
error.clear();
if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
context.GetDiagnostics()->Error(DiagMessage(container)
- << "failed to parse table: " << error);
+ << "failed to parse table: " << error);
+ error = true;
continue;
}
- printer.Indent();
- Debug::PrintTable(table, print_options, &printer);
- printer.Undent();
+ printer_->Indent();
+ Debug::PrintTable(table, print_options, printer_);
+ printer_->Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
- printer.Println("kResFile");
+ printer_->Println("kResFile");
pb::internal::CompiledFile pb_compiled_file;
off64_t offset;
size_t length;
if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
- context.GetDiagnostics()->Error(
- DiagMessage(container) << "failed to parse compiled proto file: "
- << entry->GetError());
+ context.GetDiagnostics()->Error(DiagMessage(container)
+ << "failed to parse compiled proto file: "
+ << entry->GetError());
+ error = true;
continue;
}
ResourceFile file;
if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
context.GetDiagnostics()->Warn(DiagMessage(container)
- << "failed to parse compiled file: " << error);
+ << "failed to parse compiled file: " << error);
+ error = true;
continue;
}
- printer.Indent();
- DumpCompiledFile(file, Source(container), offset, length, &printer);
- printer.Undent();
+ printer_->Indent();
+ DumpCompiledFile(file, Source(container), offset, length, printer_);
+ printer_->Undent();
}
}
}
- return 0;
+ return (error) ? 1 : 0;
}
-int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
- return 1;
- }
-
- auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
- if (!loaded_apk) {
- return 1;
- }
+int DumpBadgerCommand::Action(const std::vector<std::string>& args) {
+ printer_->Print(StringPrintf("%s", kBadgerData));
+ printer_->Print("Did you mean \"aapt2 dump badging\"?\n");
+ return 1;
+}
- ResourceTable* table = loaded_apk->GetResourceTable();
+int DumpConfigsCommand::Dump(LoadedApk* apk) {
+ ResourceTable* table = apk->GetResourceTable();
if (!table) {
- diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+ GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
// Comparison function used to order configurations
auto compare = [](android::ConfigDescription c1, android::ConfigDescription c2) -> bool {
- return c1.compare(c2) < 0;
+ return c1.compare(c2) < 0;
};
// Insert the configurations into a set in order to keep every configuarion seen
@@ -252,132 +245,93 @@ int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
// Print the configurations in order
for (auto& config : configs) {
- printer.Print(StringPrintf("%s\n", config.to_string().data()));
+ GetPrinter()->Print(StringPrintf("%s\n", config.to_string().data()));
}
-
return 0;
}
-int DumpStringsCommand::Action(const std::vector<std::string>& args) {
- DumpContext context;
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
+int DumpPackageNameCommand::Dump(LoadedApk* apk) {
+ Maybe<std::string> package_name = GetPackageName(apk);
+ if (!package_name) {
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
- for (auto apk : args) {
- auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
- if (!loaded_apk) {
- return 1;
- }
-
- ResourceTable* table = loaded_apk->GetResourceTable();
- if (!table) {
- diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
- return 1;
- }
-
- // Load the run-time xml string pool using the flattened data
- BigBuffer buffer(4096);
- StringPool::FlattenUtf8(&buffer, table->string_pool, context.GetDiagnostics());
- auto data = buffer.to_string();
- android::ResStringPool pool(data.data(), data.size(), false);
- Debug::DumpResStringPool(&pool, &printer);
- }
-
+ GetPrinter()->Println(package_name.value());
return 0;
}
-int DumpTableCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
+int DumpStringsCommand::Dump(LoadedApk* apk) {
+ ResourceTable* table = apk->GetResourceTable();
+ if (!table) {
+ GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
- DebugPrintTableOptions print_options;
- print_options.show_sources = true;
- print_options.show_values = !no_values_;
-
- for (auto apk : args) {
- auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
- if (!loaded_apk) {
- return 1;
- }
-
- if (loaded_apk->GetApkFormat() == ApkFormat::kProto) {
- printer.Println("Proto APK");
- } else {
- printer.Println("Binary APK");
- }
-
- ResourceTable* table = loaded_apk->GetResourceTable();
- if (!table) {
- diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
- return 1;
- }
-
- Debug::PrintTable(*table, print_options, &printer);
- }
-
+ // Load the run-time xml string pool using the flattened data
+ BigBuffer buffer(4096);
+ StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
+ auto data = buffer.to_string();
+ android::ResStringPool pool(data.data(), data.size(), false);
+ Debug::DumpResStringPool(&pool, GetPrinter());
return 0;
}
-int DumpXmlTreeCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified");
+int DumpStyleParentCommand::Dump(LoadedApk* apk) {
+ Maybe<std::string> package_name = GetPackageName(apk);
+ if (!package_name) {
return 1;
}
- auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
- if (!loaded_apk) {
+ const auto target_style = ResourceName(package_name.value(), ResourceType::kStyle, style_);
+ const auto table = apk->GetResourceTable();
+
+ if (!table) {
+ GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
- // Dump the xml tree of every passed in file
- for (auto file : files_) {
- auto xml = loaded_apk->LoadXml(file, diag_);
- if (!xml) {
- return 1;
- }
-
- Debug::DumpXml(*xml, &printer);
+ Maybe<ResourceTable::SearchResult> target = table->FindResource(target_style);
+ if (!target) {
+ GetDiagnostics()->Error(
+ DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist");
+ return 1;
}
+ Debug::PrintStyleGraph(table, target_style);
return 0;
}
-int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) {
- DumpContext context;
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
- return 1;
+int DumpTableCommand::Dump(LoadedApk* apk) {
+ if (apk->GetApkFormat() == ApkFormat::kProto) {
+ GetPrinter()->Println("Proto APK");
+ } else {
+ GetPrinter()->Println("Binary APK");
}
- auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
- if (!loaded_apk) {
+ ResourceTable* table = apk->GetResourceTable();
+ if (!table) {
+ GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
return 1;
}
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
+ DebugPrintTableOptions print_options;
+ print_options.show_sources = true;
+ print_options.show_values = !no_values_;
+ Debug::PrintTable(*table, print_options, GetPrinter());
+ return 0;
+}
- // Dump the xml strings of every passed in file
+int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
+ DumpContext context;
+ bool error = false;
for (auto xml_file : files_) {
android::ResXMLTree tree;
- if (loaded_apk->GetApkFormat() == ApkFormat::kProto) {
- auto xml = loaded_apk->LoadXml(xml_file, diag_);
+ if (apk->GetApkFormat() == ApkFormat::kProto) {
+ auto xml = apk->LoadXml(xml_file, GetDiagnostics());
if (!xml) {
- return 1;
+ error = true;
+ continue;
}
// Flatten the xml document to get a binary representation of the proto xml file
@@ -386,76 +340,208 @@ int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) {
options.keep_raw_values = true;
XmlFlattener flattener(&buffer, options);
if (!flattener.Consume(&context, xml.get())) {
- return 1;
+ error = true;
+ continue;
}
// Load the run-time xml tree using the flattened data
std::string data = buffer.to_string();
tree.setTo(data.data(), data.size(), /** copyData */ true);
- } else if (loaded_apk->GetApkFormat() == ApkFormat::kBinary) {
- io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file);
+ } else if (apk->GetApkFormat() == ApkFormat::kBinary) {
+ io::IFile* file = apk->GetFileCollection()->FindFile(xml_file);
if (!file) {
- diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK");
- return 1;
+ GetDiagnostics()->Error(DiagMessage(xml_file)
+ << "File '" << xml_file << "' not found in APK");
+ error = true;
+ continue;
}
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
- diag_->Error(DiagMessage() << "failed to open file");
- return 1;
+ GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file);
+ error = true;
+ continue;
}
// Load the run-time xml tree from the file data
tree.setTo(data->data(), data->size(), /** copyData */ true);
+ } else {
+ GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format");
+ error = true;
+ continue;
}
- Debug::DumpResStringPool(&tree.getStrings(), &printer);
+ Debug::DumpResStringPool(&tree.getStrings(), GetPrinter());
}
-
- return 0;
+ return (error) ? 1 : 0;
}
-int DumpPackageNameCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
- return 1;
- }
-
- auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
- if (!loaded_apk) {
- return 1;
- }
-
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- Printer printer(&fout);
-
- xml::Element* manifest_el = loaded_apk->GetManifest()->root.get();
- if (!manifest_el) {
- diag_->Error(DiagMessage() << "No AndroidManifest.");
- return 1;
- }
-
- xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
- if (!attr) {
- diag_->Error(DiagMessage() << "No package name.");
- return 1;
+int DumpXmlTreeCommand::Dump(LoadedApk* apk) {
+ for (auto file : files_) {
+ auto xml = apk->LoadXml(file, GetDiagnostics());
+ if (!xml) {
+ return 1;
+ }
+ Debug::DumpXml(*xml, GetPrinter());
}
- printer.Println(StringPrintf("%s", attr->value.c_str()));
-
return 0;
}
-/** Preform no action because a subcommand is required. */
-int DumpCommand::Action(const std::vector<std::string>& args) {
- if (args.size() == 0) {
- diag_->Error(DiagMessage() << "no subcommand specified");
- } else {
- diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
- }
-
- Usage(&std::cerr);
- return 1;
-}
+const char DumpBadgerCommand::kBadgerData[2925] = {
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 86, 35, 40, 46, 46,
+ 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 62, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 81, 81, 81, 66, 96, 61, 61, 58, 46,
+ 46, 46, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81,
+ 81, 81, 102, 59, 61, 59, 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 61, 59, 59, 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59,
+ 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 58,
+ 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 47, 61, 59, 59,
+ 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 121, 81, 91, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 81, 81, 81, 109, 58, 59, 59, 59,
+ 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81,
+ 81, 81, 81, 81, 59, 61, 59, 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 60, 81, 91, 59, 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81,
+ 81, 76, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81,
+ 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 93, 40,
+ 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 81, 68, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, 46, 32, 46,
+ 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 81, 81, 81, 87, 46, 58, 61,
+ 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46,
+ 61, 59, 61, 61, 61, 59, 61, 61, 59, 59, 59, 58, 58, 46, 46, 41, 58, 59, 58,
+ 81, 81, 81, 81, 69, 58, 59, 59, 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
+ 32, 32, 32, 32, 58, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 61, 61, 46, 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68,
+ 96, 32, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36,
+ 81, 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 67,
+ 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 61, 59, 59,
+ 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 73, 108, 108, 62, 52, 81,
+ 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 59, 61, 61, 46, 46,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 46, 45, 57, 101, 43, 43, 61,
+ 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 97,
+ 46, 61, 108, 62, 126, 58, 106, 80, 96, 46, 61, 61, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 61, 61, 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10,
+ 32, 32, 32, 32, 45, 46, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45,
+ 58, 59, 59, 59, 59, 61, 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61,
+ 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81,
+ 99, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119,
+ 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58,
+ 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 81, 58, 59, 59, 59,
+ 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 87, 66, 33, 32, 32, 32,
+ 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 45, 32, 46, 32, 32, 32, 32, 32, 46,
+ 32, 126, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 58, 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 40, 58, 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 59,
+ 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58, 58,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59,
+ 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 87, 59, 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 102, 94,
+ 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 59, 59, 43, 63, 36, 81,
+ 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 59, 59, 46, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61,
+ 59, 59, 59, 59, 59, 59, 59, 43, 33, 58, 126, 126, 58, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59,
+ 58, 95, 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59,
+ 59, 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 59, 58,
+ 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 59, 59, 59, 59, 59, 59,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45,
+ 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61,
+ 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32,
+ 32, 32, 32, 32, 32, 61, 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59,
+ 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59,
+ 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 32,
+ 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 59, 59, 59, 59,
+ 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 58, 45,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10};
} // namespace aapt
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 9ec820d89596..89d19cf4ba08 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -19,14 +19,77 @@
#include "Command.h"
#include "Debug.h"
+#include "LoadedApk.h"
#include "dump/DumpManifest.h"
namespace aapt {
-/** Command the contents of files generated from the compilation stage. */
+/**
+ * The base command for dumping information about apks. When the command is executed, the command
+ * performs the DumpApkCommand::Dump() operation on each apk provided as a file argument.
+ **/
+class DumpApkCommand : public Command {
+ public:
+ explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
+ : Command(name), printer_(printer), diag_(diag) {
+ }
+
+ text::Printer* GetPrinter() {
+ return printer_;
+ }
+
+ IDiagnostics* GetDiagnostics() {
+ return diag_;
+ }
+
+ Maybe<std::string> GetPackageName(LoadedApk* apk) {
+ xml::Element* manifest_el = apk->GetManifest()->root.get();
+ if (!manifest_el) {
+ GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
+ return Maybe<std::string>();
+ }
+
+ xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
+ if (!attr) {
+ GetDiagnostics()->Error(DiagMessage() << "No package name.");
+ return Maybe<std::string>();
+ }
+ return attr->value;
+ }
+
+ /** Perform the dump operation on the apk. */
+ virtual int Dump(LoadedApk* apk) = 0;
+
+ int Action(const std::vector<std::string>& args) final {
+ if (args.size() < 1) {
+ diag_->Error(DiagMessage() << "No dump apk specified.");
+ return 1;
+ }
+
+ bool error = false;
+ for (auto apk : args) {
+ auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+ if (!loaded_apk) {
+ error = true;
+ continue;
+ }
+
+ error |= Dump(loaded_apk.get());
+ }
+
+ return error;
+ }
+
+ private:
+ text::Printer* printer_;
+ IDiagnostics* diag_;
+};
+
+/** Command that prints contents of files generated from the compilation stage. */
class DumpAPCCommand : public Command {
public:
- explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) {
+ explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag)
+ : Command("apc"), printer_(printer), diag_(diag) {
SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
&no_values_);
@@ -36,120 +99,178 @@ class DumpAPCCommand : public Command {
int Action(const std::vector<std::string>& args) override;
private:
+ text::Printer* printer_;
IDiagnostics* diag_;
- bool verbose_ = false;
bool no_values_ = false;
+ bool verbose_ = false;
};
-/** Prints every configuration used by a resource in an APK. */
-class DumpConfigsCommand : public Command {
+/** Easter egg command shown when users enter "badger" instead of "badging". */
+class DumpBadgerCommand : public Command {
public:
- explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) {
- SetDescription("Print every configuration used by a resource in the APK.");
+ explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) {
}
int Action(const std::vector<std::string>& args) override;
private:
- IDiagnostics* diag_;
+ text::Printer* printer_;
+ const static char kBadgerData[2925];
};
-/** Prints the contents of the resource table string pool in the APK. */
-class DumpStringsCommand : public Command {
- public:
- explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) {
- SetDescription("Print the contents of the resource table string pool in the APK.");
- }
+class DumpBadgingCommand : public DumpApkCommand {
+ public:
+ explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("badging", printer, diag) {
+ SetDescription("Print information extracted from the manifest of the APK.");
+ AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
+ &options_.include_meta_data);
+ }
- int Action(const std::vector<std::string>& args) override;
+ int Dump(LoadedApk* apk) override {
+ return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
+ }
- private:
- IDiagnostics* diag_;
+ private:
+ DumpManifestOptions options_;
};
-/** Prints the contents of the resource table from the APK. */
-class DumpTableCommand : public Command {
+class DumpConfigsCommand : public DumpApkCommand {
public:
- explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) {
+ explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("configurations", printer, diag) {
+ SetDescription("Print every configuration used by a resource in the APK.");
+ }
+
+ int Dump(LoadedApk* apk) override;
+};
+
+class DumpPackageNameCommand : public DumpApkCommand {
+ public:
+ explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("packagename", printer, diag) {
+ SetDescription("Print the package name of the APK.");
+ }
+
+ int Dump(LoadedApk* apk) override;
+};
+
+class DumpPermissionsCommand : public DumpApkCommand {
+ public:
+ explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("permissions", printer, diag) {
+ SetDescription("Print the permissions extracted from the manifest of the APK.");
+ }
+
+ int Dump(LoadedApk* apk) override {
+ DumpManifestOptions options;
+ options.only_permissions = true;
+ return DumpManifest(apk, options, GetPrinter(), GetDiagnostics());
+ }
+};
+
+class DumpStringsCommand : public DumpApkCommand {
+ public:
+ explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("strings", printer, diag) {
+ SetDescription("Print the contents of the resource table string pool in the APK.");
+ }
+
+ int Dump(LoadedApk* apk) override;
+};
+
+/** Prints the graph of parents of a style in an APK. */
+class DumpStyleParentCommand : public DumpApkCommand {
+ public:
+ explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("styleparents", printer, diag) {
+ SetDescription("Print the parents of a style in an APK.");
+ AddRequiredFlag("--style", "The name of the style to print", &style_);
+ }
+
+ int Dump(LoadedApk* apk) override;
+
+ private:
+ std::string style_;
+};
+
+class DumpTableCommand : public DumpApkCommand {
+ public:
+ explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("resources", printer, diag) {
SetDescription("Print the contents of the resource table from the APK.");
AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
&no_values_);
AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
}
- int Action(const std::vector<std::string>& args) override;
+ int Dump(LoadedApk* apk) override;
private:
- IDiagnostics* diag_;
- bool verbose_ = false;
bool no_values_ = false;
+ bool verbose_ = false;
};
-/** Prints the string pool of a compiled xml in an APK. */
-class DumpXmlStringsCommand : public Command {
-public:
- explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) {
- SetDescription("Print the string pool of a compiled xml in an APK.");
- AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
- }
-
- int Action(const std::vector<std::string>& args) override;
-
-private:
- IDiagnostics* diag_;
- std::vector<std::string> files_;
-};
-
-
-/** Prints the tree of a compiled xml in an APK. */
-class DumpXmlTreeCommand : public Command {
+class DumpXmlStringsCommand : public DumpApkCommand {
public:
- explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) {
- SetDescription("Print the tree of a compiled xml in an APK.");
+ explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("xmlstrings", printer, diag) {
+ SetDescription("Print the string pool of a compiled xml in an APK.");
AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
}
- int Action(const std::vector<std::string>& args) override;
+ int Dump(LoadedApk* apk) override;
private:
- IDiagnostics* diag_;
std::vector<std::string> files_;
};
-/** Prints the contents of the resource table from the APK. */
-class DumpPackageNameCommand : public Command {
+class DumpXmlTreeCommand : public DumpApkCommand {
public:
- explicit DumpPackageNameCommand(IDiagnostics* diag) : Command("packagename"), diag_(diag) {
- SetDescription("Print the package name of the APK.");
+ explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
+ : DumpApkCommand("xmltree", printer, diag) {
+ SetDescription("Print the tree of a compiled xml in an APK.");
+ AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
}
- int Action(const std::vector<std::string>& args) override;
+ int Dump(LoadedApk* apk) override;
private:
- IDiagnostics* diag_;
+ std::vector<std::string> files_;
};
/** The default dump command. Performs no action because a subcommand is required. */
class DumpCommand : public Command {
public:
- explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) {
- AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_));
- AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(diag_));
+ explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
+ : Command("dump", "d"), diag_(diag) {
+ AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
+ AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
}
- int Action(const std::vector<std::string>& args) override;
+ int Action(const std::vector<std::string>& args) override {
+ if (args.size() == 0) {
+ diag_->Error(DiagMessage() << "no subcommand specified");
+ } else {
+ diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+ }
+ Usage(&std::cerr);
+ return 1;
+ }
private:
IDiagnostics* diag_;
};
-}// namespace aapt
+} // namespace aapt
-#endif //AAPT2_DUMP_H
+#endif // AAPT2_DUMP_H
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 186f8a159fe7..6a7da0c57df3 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1776,10 +1776,12 @@ class Linker {
// Before we process anything, remove the resources whose default values don't exist.
// We want to force any references to these to fail the build.
- if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "failed removing resources with no defaults");
- return 1;
+ if (!options_.no_resource_removal) {
+ if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed removing resources with no defaults");
+ return 1;
+ }
}
ReferenceLinker linker;
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index a42c0f250e3e..950dac204dde 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -59,6 +59,7 @@ struct LinkOptions {
bool no_version_vectors = false;
bool no_version_transitions = false;
bool no_resource_deduping = false;
+ bool no_resource_removal = false;
bool no_xml_namespaces = false;
bool do_not_compress_anything = false;
std::unordered_set<std::string> extensions_to_not_compress;
@@ -136,6 +137,9 @@ class LinkCommand : public Command {
AddOptionalSwitch("--no-resource-deduping", "Disables automatic deduping of resources with\n"
"identical values across compatible configurations.",
&options_.no_resource_deduping);
+ AddOptionalSwitch("--no-resource-removal", "Disables automatic removal of resources without\n"
+ "defaults. Use this only when building runtime resource overlay packages.",
+ &options_.no_resource_removal);
AddOptionalSwitch("--enable-sparse-encoding",
"This decreases APK size at the cost of resource retrieval performance.",
&options_.table_flattener_options.use_sparse_entries);
@@ -280,4 +284,4 @@ class LinkCommand : public Command {
}// namespace aapt
-#endif //AAPT2_LINK_H \ No newline at end of file
+#endif //AAPT2_LINK_H
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index c0e1dc682845..11a4074cd3cd 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -109,15 +109,8 @@ class CommonFeatureGroup;
class ManifestExtractor {
public:
- struct Options {
- /** Include meta information from <meta-data> elements in the output. */
- bool include_meta_data = false;
- /** Only output permission information. */
- bool only_permissions = false;
- };
-
- explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options)
+ explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
: apk_(apk), options_(options) { }
class Element {
@@ -128,7 +121,7 @@ class ManifestExtractor {
static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
/** Writes out the extracted contents of the element. */
- virtual void Print(text::Printer& printer) { }
+ virtual void Print(text::Printer* printer) { }
/** Adds an element to the list of children of the element. */
void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
@@ -332,7 +325,7 @@ class ManifestExtractor {
return config;
}
- bool Dump(text::Printer& printer, IDiagnostics* diag);
+ bool Dump(text::Printer* printer, IDiagnostics* diag);
/** Recursively visit the xml element tree and return a processed badging element tree. */
std::unique_ptr<Element> Visit(xml::Element* element);
@@ -378,7 +371,7 @@ class ManifestExtractor {
}
LoadedApk* const apk_;
- const Options options_;
+ DumpManifestOptions& options_;
private:
std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
@@ -450,40 +443,40 @@ class Manifest : public ManifestExtractor::Element {
installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
}
- void Print(text::Printer& printer) override {
- printer.Print(StringPrintf("package: name='%s' ", package.data()));
- printer.Print(StringPrintf("versionCode='%s' ",
+ void Print(text::Printer* printer) override {
+ printer->Print(StringPrintf("package: name='%s' ", package.data()));
+ printer->Print(StringPrintf("versionCode='%s' ",
(versionCode > 0) ? std::to_string(versionCode).data() : ""));
- printer.Print(StringPrintf("versionName='%s'", versionName.data()));
+ printer->Print(StringPrintf("versionName='%s'", versionName.data()));
if (split) {
- printer.Print(StringPrintf(" split='%s'", split->data()));
+ printer->Print(StringPrintf(" split='%s'", split->data()));
}
if (platformVersionName) {
- printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
+ printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
}
if (platformVersionCode) {
- printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
+ printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
}
if (compilesdkVersion) {
- printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
+ printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
}
if (compilesdkVersionCodename) {
- printer.Print(StringPrintf(" compileSdkVersionCodename='%s'",
+ printer->Print(StringPrintf(" compileSdkVersionCodename='%s'",
compilesdkVersionCodename->data()));
}
- printer.Print("\n");
+ printer->Print("\n");
if (installLocation) {
switch (*installLocation) {
case 0:
- printer.Print("install-location:'auto'\n");
+ printer->Print("install-location:'auto'\n");
break;
case 1:
- printer.Print("install-location:'internalOnly'\n");
+ printer->Print("install-location:'internalOnly'\n");
break;
case 2:
- printer.Print("install-location:'preferExternal'\n");
+ printer->Print("install-location:'preferExternal'\n");
break;
default:
break;
@@ -544,15 +537,15 @@ class Application : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
// Print the labels for every locale
for (auto p : locale_labels) {
if (p.first.empty()) {
- printer.Print(StringPrintf("application-label:'%s'\n",
+ printer->Print(StringPrintf("application-label:'%s'\n",
android::ResTable::normalizeForOutput(p.second.data())
.c_str()));
} else {
- printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
+ printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
android::ResTable::normalizeForOutput(p.second.data())
.c_str()));
}
@@ -560,26 +553,26 @@ class Application : public ManifestExtractor::Element {
// Print the icon paths for every density
for (auto p : density_icons) {
- printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
+ printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
}
// Print the application info
- printer.Print(StringPrintf("application: label='%s' ",
+ printer->Print(StringPrintf("application: label='%s' ",
android::ResTable::normalizeForOutput(label.data()).c_str()));
- printer.Print(StringPrintf("icon='%s'", icon.data()));
+ printer->Print(StringPrintf("icon='%s'", icon.data()));
if (!banner.empty()) {
- printer.Print(StringPrintf(" banner='%s'", banner.data()));
+ printer->Print(StringPrintf(" banner='%s'", banner.data()));
}
- printer.Print("\n");
+ printer->Print("\n");
if (test_only != 0) {
- printer.Print(StringPrintf("testOnly='%d'\n", test_only));
+ printer->Print(StringPrintf("testOnly='%d'\n", test_only));
}
if (is_game != 0) {
- printer.Print("application-isGame\n");
+ printer->Print("application-isGame\n");
}
if (debuggable != 0) {
- printer.Print("application-debuggable\n");
+ printer->Print("application-debuggable\n");
}
}
};
@@ -614,19 +607,19 @@ class UsesSdkBadging : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (min_sdk) {
- printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
+ printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
} else if (min_sdk_name) {
- printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
+ printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
}
if (max_sdk) {
- printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
+ printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
}
if (target_sdk) {
- printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
+ printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
} else if (target_sdk_name) {
- printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
+ printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
}
}
};
@@ -654,24 +647,24 @@ class UsesConfiguarion : public ManifestExtractor::Element {
FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
}
- void Print(text::Printer& printer) override {
- printer.Print("uses-configuration:");
+ void Print(text::Printer* printer) override {
+ printer->Print("uses-configuration:");
if (req_touch_screen != 0) {
- printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
+ printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
}
if (req_keyboard_type != 0) {
- printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
+ printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
}
if (req_hard_keyboard != 0) {
- printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
+ printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
}
if (req_navigation != 0) {
- printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation));
+ printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation));
}
if (req_five_way_nav != 0) {
- printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
+ printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
}
- printer.Print("\n");
+ printer->Print("\n");
}
};
@@ -715,7 +708,7 @@ class SupportsScreen : public ManifestExtractor::Element {
}
}
- void PrintScreens(text::Printer& printer, int32_t target_sdk) {
+ void PrintScreens(text::Printer* printer, int32_t target_sdk) {
int32_t small_screen_temp = small_screen;
int32_t normal_screen_temp = normal_screen;
int32_t large_screen_temp = large_screen;
@@ -745,30 +738,30 @@ class SupportsScreen : public ManifestExtractor::Element {
}
// Print the formatted screen info
- printer.Print("supports-screens:");
+ printer->Print("supports-screens:");
if (small_screen_temp != 0) {
- printer.Print(" 'small'");
+ printer->Print(" 'small'");
}
if (normal_screen_temp != 0) {
- printer.Print(" 'normal'");
+ printer->Print(" 'normal'");
}
if (large_screen_temp != 0) {
- printer.Print(" 'large'");
+ printer->Print(" 'large'");
}
if (xlarge_screen_temp != 0) {
- printer.Print(" 'xlarge'");
+ printer->Print(" 'xlarge'");
}
- printer.Print("\n");
- printer.Print(StringPrintf("supports-any-density: '%s'\n",
+ printer->Print("\n");
+ printer->Print(StringPrintf("supports-any-density: '%s'\n",
(any_density_temp ) ? "true" : "false"));
if (requires_smallest_width_dp > 0) {
- printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
+ printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
}
if (compatible_width_limit_dp > 0) {
- printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
+ printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
}
if (largest_width_limit_dp > 0) {
- printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
+ printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
}
}
};
@@ -784,20 +777,20 @@ class FeatureGroup : public ManifestExtractor::Element {
label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
}
- virtual void PrintGroup(text::Printer& printer) {
- printer.Print(StringPrintf("feature-group: label='%s'\n", label.data()));
+ virtual void PrintGroup(text::Printer* printer) {
+ printer->Print(StringPrintf("feature-group: label='%s'\n", label.data()));
if (open_gles_version > 0) {
- printer.Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
+ printer->Print(StringPrintf(" uses-gl-es: '0x%x'\n", open_gles_version));
}
for (auto feature : features_) {
- printer.Print(StringPrintf(" uses-feature%s: name='%s'",
+ printer->Print(StringPrintf(" uses-feature%s: name='%s'",
(feature.second.required ? "" : "-not-required"),
feature.first.data()));
if (feature.second.version > 0) {
- printer.Print(StringPrintf(" version='%d'", feature.second.version));
+ printer->Print(StringPrintf(" version='%d'", feature.second.version));
}
- printer.Print("\n");
+ printer->Print("\n");
}
}
@@ -863,29 +856,29 @@ class FeatureGroup : public ManifestExtractor::Element {
class CommonFeatureGroup : public FeatureGroup {
public:
CommonFeatureGroup() = default;
- void PrintGroup(text::Printer& printer) override {
+ void PrintGroup(text::Printer* printer) override {
FeatureGroup::PrintGroup(printer);
// Also print the implied features
for (auto feature : implied_features_) {
if (features_.find(feature.first) == features_.end()) {
const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
- printer.Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
- printer.Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
+ printer->Print(StringPrintf(" uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
+ printer->Print(StringPrintf(" uses-implied-feature%s: name='%s' reason='", sdk23,
feature.first.data()));
// Print the reasons as a sentence
size_t count = 0;
for (auto reason : feature.second.reasons) {
- printer.Print(reason);
+ printer->Print(reason);
if (count + 2 < feature.second.reasons.size()) {
- printer.Print(", ");
+ printer->Print(", ");
} else if (count + 1 < feature.second.reasons.size()) {
- printer.Print(", and ");
+ printer->Print(", and ");
}
count++;
}
- printer.Print("'\n");
+ printer->Print("'\n");
}
}
}
@@ -1070,35 +1063,35 @@ class UsesPermission : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (!name.empty()) {
- printer.Print(StringPrintf("uses-permission: name='%s'", name.data()));
+ printer->Print(StringPrintf("uses-permission: name='%s'", name.data()));
if (maxSdkVersion >= 0) {
- printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
}
if (!requiredFeature.empty()) {
- printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
+ printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
}
if (!requiredNotFeature.empty()) {
- printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
+ printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
}
- printer.Print("\n");
+ printer->Print("\n");
if (required == 0) {
- printer.Print(StringPrintf("optional-permission: name='%s'", name.data()));
+ printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
if (maxSdkVersion >= 0) {
- printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
}
- printer.Print("\n");
+ printer->Print("\n");
}
}
}
- void PrintImplied(text::Printer& printer, const std::string& reason) {
- printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+ void PrintImplied(text::Printer* printer, const std::string& reason) {
+ printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
if (maxSdkVersion >= 0) {
- printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
}
- printer.Print(StringPrintf(" reason='%s'\n", reason.data()));
+ printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
}
};
@@ -1119,13 +1112,13 @@ class UsesPermissionSdk23 : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (name) {
- printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
+ printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
if (maxSdkVersion) {
- printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
+ printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
}
- printer.Print("\n");
+ printer->Print("\n");
}
}
};
@@ -1140,9 +1133,9 @@ class Permission : public ManifestExtractor::Element {
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (extractor()->options_.only_permissions && !name.empty()) {
- printer.Print(StringPrintf("permission: %s\n", name.data()));
+ printer->Print(StringPrintf("permission: %s\n", name.data()));
}
}
};
@@ -1202,25 +1195,25 @@ class Activity : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
// Print whether the activity has the HOME category and a the MAIN action
if (has_main_action && has_launcher_category) {
- printer.Print("launchable-activity:");
+ printer->Print("launchable-activity:");
if (!name.empty()) {
- printer.Print(StringPrintf(" name='%s' ", name.data()));
+ printer->Print(StringPrintf(" name='%s' ", name.data()));
}
- printer.Print(StringPrintf(" label='%s' icon='%s'\n",
+ printer->Print(StringPrintf(" label='%s' icon='%s'\n",
android::ResTable::normalizeForOutput(label.data()).c_str(),
icon.data()));
}
// Print wether the activity has the HOME category and a the MAIN action
if (has_leanback_launcher_category) {
- printer.Print("leanback-launchable-activity:");
+ printer->Print("leanback-launchable-activity:");
if (!name.empty()) {
- printer.Print(StringPrintf(" name='%s' ", name.data()));
+ printer->Print(StringPrintf(" name='%s' ", name.data()));
}
- printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
+ printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
android::ResTable::normalizeForOutput(label.data()).c_str(),
icon.data(), banner.data()));
}
@@ -1319,9 +1312,9 @@ class UsesLibrary : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (!name.empty()) {
- printer.Print(StringPrintf("uses-library%s:'%s'\n",
+ printer->Print(StringPrintf("uses-library%s:'%s'\n",
(required == 0) ? "-not-required" : "", name.data()));
}
}
@@ -1344,8 +1337,8 @@ class StaticLibrary : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
- printer.Print(StringPrintf(
+ void Print(text::Printer* printer) override {
+ printer->Print(StringPrintf(
"static-library: name='%s' version='%d' versionMajor='%d'\n",
name.data(), version, versionMajor));
}
@@ -1380,14 +1373,14 @@ class UsesStaticLibrary : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
- printer.Print(StringPrintf(
+ void Print(text::Printer* printer) override {
+ printer->Print(StringPrintf(
"uses-static-library: name='%s' version='%d' versionMajor='%d'",
name.data(), version, versionMajor));
for (size_t i = 0; i < certDigests.size(); i++) {
- printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+ printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
}
- printer.Print("\n");
+ printer->Print("\n");
}
};
@@ -1412,21 +1405,21 @@ class MetaData : public ManifestExtractor::Element {
resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (extractor()->options_.include_meta_data && !name.empty()) {
- printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
+ printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
if (!value.empty()) {
- printer.Print(StringPrintf("value='%s' ", value.data()));
+ printer->Print(StringPrintf("value='%s' ", value.data()));
} else if (value_int) {
- printer.Print(StringPrintf("value='%d' ", *value_int));
+ printer->Print(StringPrintf("value='%d' ", *value_int));
} else {
if (!resource.empty()) {
- printer.Print(StringPrintf("resource='%s' ", resource.data()));
+ printer->Print(StringPrintf("resource='%s' ", resource.data()));
} else if (resource_int) {
- printer.Print(StringPrintf("resource='%d' ", *resource_int));
+ printer->Print(StringPrintf("resource='%d' ", *resource_int));
}
}
- printer.Print("\n");
+ printer->Print("\n");
}
}
};
@@ -1548,14 +1541,14 @@ class SupportsInput : public ManifestExtractor::Element {
SupportsInput() = default;
std::vector<std::string> inputs;
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
const size_t size = inputs.size();
if (size > 0) {
- printer.Print("supports-input: '");
+ printer->Print("supports-input: '");
for (size_t i = 0; i < size; i++) {
- printer.Print(StringPrintf("value='%s' ", inputs[i].data()));
+ printer->Print(StringPrintf("value='%s' ", inputs[i].data()));
}
- printer.Print("\n");
+ printer->Print("\n");
}
}
};
@@ -1586,9 +1579,9 @@ class OriginalPackage : public ManifestExtractor::Element {
name = GetAttributeString(FindAttribute(element, NAME_ATTR));
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (name) {
- printer.Print(StringPrintf("original-package:'%s'\n", name->data()));
+ printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
}
}
};
@@ -1605,9 +1598,9 @@ class PackageVerifier : public ManifestExtractor::Element {
public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (name && public_key) {
- printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
+ printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
name->data(), public_key->data()));
}
}
@@ -1644,18 +1637,18 @@ class UsesPackage : public ManifestExtractor::Element {
}
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (name) {
if (packageType) {
- printer.Print(StringPrintf(
+ printer->Print(StringPrintf(
"uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
packageType->data(), name->data(), version, versionMajor));
for (size_t i = 0; i < certDigests.size(); i++) {
- printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+ printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
}
- printer.Print("\n");
+ printer->Print("\n");
} else {
- printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+ printer->Print(StringPrintf("uses-package:'%s'\n", name->data()));
}
}
}
@@ -1700,8 +1693,8 @@ class Screen : public ManifestExtractor::Element {
class CompatibleScreens : public ManifestExtractor::Element {
public:
CompatibleScreens() = default;
- void Print(text::Printer& printer) override {
- printer.Print("compatible-screens:");
+ void Print(text::Printer* printer) override {
+ printer->Print("compatible-screens:");
bool first = true;
ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
@@ -1709,15 +1702,15 @@ class CompatibleScreens : public ManifestExtractor::Element {
if (first) {
first = false;
} else {
- printer.Print(",");
+ printer->Print(",");
}
if (screen->size && screen->density) {
- printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
+ printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
}
}
});
- printer.Print("\n");
+ printer->Print("\n");
}
};
@@ -1731,22 +1724,22 @@ class SupportsGlTexture : public ManifestExtractor::Element {
name = GetAttributeString(FindAttribute(element, NAME_ATTR));
}
- void Print(text::Printer& printer) override {
+ void Print(text::Printer* printer) override {
if (name) {
- printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
+ printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
}
}
};
/** Recursively prints the extracted badging element. */
-static void Print(ManifestExtractor::Element* el, text::Printer& printer) {
+static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
el->Print(printer);
for (auto &child : el->children()) {
Print(child.get(), printer);
}
}
-bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
+bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
// Load the manifest
std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
if (doc == nullptr) {
@@ -1775,7 +1768,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
}
}
- printer.Print(StringPrintf("package: %s\n", manifest->package.data()));
+ printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
el->Print(printer);
});
@@ -1992,7 +1985,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
// Print the components types if they are present
auto PrintComponent = [&components, &printer](const std::string& component) -> void {
if (components.find(component) != components.end()) {
- printer.Print(StringPrintf("provides-component:'%s'\n", component.data()));
+ printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
}
};
@@ -2013,14 +2006,14 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
// Print presence of main activity
if (components.find("main") != components.end()) {
- printer.Print("main\n");
+ printer->Print("main\n");
}
// Print presence of activities, recivers, and services with no special components
FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
if (auto activity = ElementCast<Activity>(el)) {
if (!activity->has_component_) {
- printer.Print("other-activities\n");
+ printer->Print("other-activities\n");
return true;
}
}
@@ -2030,7 +2023,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
if (auto receiver = ElementCast<Receiver>(el)) {
if (!receiver->has_component) {
- printer.Print("other-receivers\n");
+ printer->Print("other-receivers\n");
return true;
}
}
@@ -2040,7 +2033,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
if (auto service = ElementCast<Service>(el)) {
if (!service->has_component) {
- printer.Print("other-services\n");
+ printer->Print("other-services\n");
return true;
}
}
@@ -2062,22 +2055,22 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
}
// Print all the unique locales of the apk
- printer.Print("locales:");
+ printer->Print("locales:");
for (auto& config : locales_) {
if (config.first.empty()) {
- printer.Print(" '--_--'");
+ printer->Print(" '--_--'");
} else {
- printer.Print(StringPrintf(" '%s'", config.first.data()));
+ printer->Print(StringPrintf(" '%s'", config.first.data()));
}
}
- printer.Print("\n");
+ printer->Print("\n");
// Print all the densities locales of the apk
- printer.Print("densities:");
+ printer->Print("densities:");
for (auto& config : densities_) {
- printer.Print(StringPrintf(" '%d'", config.first));
+ printer->Print(StringPrintf(" '%d'", config.first));
}
- printer.Print("\n");
+ printer->Print("\n");
// Print the supported architectures of the app
std::set<std::string> architectures;
@@ -2131,7 +2124,7 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
}
if (arch != architectures.end()) {
- printer.Print(StringPrintf("native-code: '%s'\n", arch->data()));
+ printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
architectures.erase(arch);
output_alt_native_code = true;
}
@@ -2139,13 +2132,13 @@ bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
if (architectures.size() > 0) {
if (output_alt_native_code) {
- printer.Print("alt-");
+ printer->Print("alt-");
}
- printer.Print("native-code:");
+ printer->Print("native-code:");
for (auto& arch : architectures) {
- printer.Print(StringPrintf(" '%s'", arch.data()));
+ printer->Print(StringPrintf(" '%s'", arch.data()));
}
- printer.Print("\n");
+ printer->Print("\n");
}
return true;
@@ -2272,55 +2265,11 @@ std::unique_ptr<ManifestExtractor::Element> ManifestExtractor::Visit(xml::Elemen
return element;
}
-// Use a smaller buffer so that there is less latency for dumping to stdout.
-constexpr size_t kStdOutBufferSize = 1024u;
-
-int DumpBadgingCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
- return 1;
- }
-
- ManifestExtractor::Options options;
- options.include_meta_data = include_metadata_;
-
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- text::Printer printer(&fout);
- for (auto apk : args) {
- auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
- if (!loaded_apk) {
- return 1;
- }
-
- ManifestExtractor extractor(loaded_apk.get(), options);
- extractor.Dump(printer, diag_);
- }
-
- return 0;
-}
-
-int DumpPermissionsCommand::Action(const std::vector<std::string>& args) {
- if (args.size() < 1) {
- diag_->Error(DiagMessage() << "No dump apk specified.");
- return 1;
- }
-
- ManifestExtractor::Options options;
- options.only_permissions = true;
-
- io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
- text::Printer printer(&fout);
- for (auto apk : args) {
- auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
- if (!loaded_apk) {
- return 1;
- }
-
- ManifestExtractor extractor(loaded_apk.get(), options);
- extractor.Dump(printer, diag_);
- }
- return 0;
+int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
+ IDiagnostics* diag) {
+ ManifestExtractor extractor(apk, options);
+ return extractor.Dump(printer, diag);
}
} // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
index a70be53fa070..daf22ed57a84 100644
--- a/tools/aapt2/dump/DumpManifest.h
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -17,45 +17,23 @@
#ifndef AAPT2_DUMP_MANIFEST_H
#define AAPT2_DUMP_MANIFEST_H
-#include <Diagnostics.h>
-#include <ValueVisitor.h>
-#include <io/ZipArchive.h>
-
-
-#include "cmd/Command.h"
-#include "process/IResourceTableConsumer.h"
+#include "Diagnostics.h"
+#include "LoadedApk.h"
#include "text/Printer.h"
-#include "xml/XmlDom.h"
namespace aapt {
-class DumpBadgingCommand : public Command {
- public:
- explicit DumpBadgingCommand(IDiagnostics* diag) : Command("badging"), diag_(diag) {
- SetDescription("Print information extracted from the manifest of the APK.");
- AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
- &include_metadata_);
- }
-
- int Action(const std::vector<std::string>& args) override;
-
- private:
- IDiagnostics* diag_;
- bool include_metadata_ = false;
+struct DumpManifestOptions {
+ /** Include meta information from <meta-data> elements in the output. */
+ bool include_meta_data = false;
+ /** Only output permission information. */
+ bool only_permissions = false;
};
-class DumpPermissionsCommand : public Command {
- public:
- explicit DumpPermissionsCommand(IDiagnostics* diag) : Command("permissions"), diag_(diag) {
- SetDescription("Print the permissions extracted from the manifest of the APK.");
- }
-
- int Action(const std::vector<std::string>& args) override;
-
- private:
- IDiagnostics* diag_;
-};
+/** Print information extracted from the manifest of the APK. */
+int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
+ IDiagnostics* diag);
-}// namespace aapt
+} // namespace aapt
-#endif //AAPT2_DUMP_MANIFEST_H \ No newline at end of file
+#endif // AAPT2_DUMP_MANIFEST_H \ No newline at end of file
diff --git a/tools/hiddenapi/sort_api.sh b/tools/hiddenapi/sort_api.sh
index 76a2f2d6eba1..710da40585ac 100755
--- a/tools/hiddenapi/sort_api.sh
+++ b/tools/hiddenapi/sort_api.sh
@@ -21,4 +21,6 @@ A=( $(uniq <<< "${A[*]}") )
A=( ${C[*]} ${A[*]} )
unset IFS
# Dump array back into the file
-printf '%s\n' "${A[@]}" > "$dest_list"
+if [ ${#A[@]} -ne 0 ]; then
+ printf '%s\n' "${A[@]}" > "$dest_list"
+fi
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 4245700ed90d..d1f42f8b398e 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -251,7 +251,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
}
atomDecl->fields.push_back(atField);
- if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
+ if (field->options().GetExtension(os::statsd::state_field_option).option() ==
os::statsd::StateField::PRIMARY) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
@@ -261,7 +261,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
atomDecl->primaryFields.push_back(it->first);
}
- if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
+ if (field->options().GetExtension(os::statsd::state_field_option).option() ==
os::statsd::StateField::EXCLUSIVE) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 264a865e3b39..f6359748a27e 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -127,33 +127,33 @@ message GoodStateAtoms {
// The atom has only primary field but no exclusive state field.
message BadStateAtom1 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
}
// Only primative types can be annotated.
message BadStateAtom2 {
repeated android.os.statsd.AttributionNode attribution = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// Having 2 exclusive state field in the atom means the atom is badly designed.
// E.g., putting bluetooth state and wifi state in the same atom.
message BadStateAtom3 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
optional int32 state2 = 3
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
message GoodStateAtom1 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// Atoms can have exclusive state field, but no primary field. That means
@@ -161,16 +161,16 @@ message GoodStateAtom1 {
message GoodStateAtom2 {
optional int32 uid = 1;
optional int32 state = 2
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
// We can have more than one primary fields. That means their combination is a
// primary key.
message GoodStateAtom3 {
optional int32 uid = 1
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 tid = 2
- [(android.os.statsd.stateFieldOption).option = PRIMARY];
+ [(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 3
- [(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
+ [(android.os.statsd.state_field_option).option = EXCLUSIVE];
} \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
deleted file mode 100644
index f5cad139bd23..000000000000
--- a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A class representing wifi wake reason accounting.
- */
-
-/** @hide */
-public class WifiWakeReasonAndCounts implements Parcelable {
- private static final String TAG = "WifiWakeReasonAndCounts";
- /**
- * Wlan can wake host, only when it is cmd/event, local driver-fw
- * functions(non-data, non cmd/event) and rx data.The first packet
- * from wlan that woke up a sleep host is what is accounted here.
- * Total wlan wake to application processor would be:
- * [cmdEventWake + driverFwLocalWake + totalRxDataWake]
- * A further classification is provided for identifying the reasons
- * for wakeup.
- */
- public int totalCmdEventWake;
- public int totalDriverFwLocalWake;
- public int totalRxDataWake;
-
- public int rxUnicast;
- public int rxMulticast;
- public int rxBroadcast;
-
- public int icmp;
- public int icmp6;
- public int icmp6Ra;
- public int icmp6Na;
- public int icmp6Ns;
-
- public int ipv4RxMulticast;
- public int ipv6Multicast;
- public int otherRxMulticast;
- public int[] cmdEventWakeCntArray;
- public int[] driverFWLocalWakeCntArray;
-
- /* {@hide} */
- public WifiWakeReasonAndCounts () {
- }
-
- @Override
- /* {@hide} */
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append(" totalCmdEventWake ").append(totalCmdEventWake);
- sb.append(" totalDriverFwLocalWake ").append(totalDriverFwLocalWake);
- sb.append(" totalRxDataWake ").append(totalRxDataWake);
-
- sb.append(" rxUnicast ").append(rxUnicast);
- sb.append(" rxMulticast ").append(rxMulticast);
- sb.append(" rxBroadcast ").append(rxBroadcast);
-
- sb.append(" icmp ").append(icmp);
- sb.append(" icmp6 ").append(icmp6);
- sb.append(" icmp6Ra ").append(icmp6Ra);
- sb.append(" icmp6Na ").append(icmp6Na);
- sb.append(" icmp6Ns ").append(icmp6Ns);
-
- sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
- sb.append(" ipv6Multicast ").append(ipv6Multicast);
- sb.append(" otherRxMulticast ").append(otherRxMulticast);
- for (int i = 0; i < cmdEventWakeCntArray.length; i++) {
- sb.append(" cmdEventWakeCntArray[" + i + "] " + cmdEventWakeCntArray[i]);
- }
- for (int i = 0; i < driverFWLocalWakeCntArray.length; i++) {
- sb.append(" driverFWLocalWakeCntArray[" + i + "] " + driverFWLocalWakeCntArray[i]);
- }
-
- return sb.toString();
- }
-
- /* Implement the Parcelable interface
- * {@hide}
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /* Implement the Parcelable interface
- * {@hide}
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(totalCmdEventWake);
- dest.writeInt(totalDriverFwLocalWake);
- dest.writeInt(totalRxDataWake);
-
- dest.writeInt(rxUnicast);
- dest.writeInt(rxMulticast);
- dest.writeInt(rxBroadcast);
-
- dest.writeInt(icmp);
- dest.writeInt(icmp6);
- dest.writeInt(icmp6Ra);
- dest.writeInt(icmp6Na);
- dest.writeInt(icmp6Ns);
-
- dest.writeInt(ipv4RxMulticast);
- dest.writeInt(ipv6Multicast);
- dest.writeInt(otherRxMulticast);
- dest.writeIntArray(cmdEventWakeCntArray);
- dest.writeIntArray(driverFWLocalWakeCntArray);
- }
-
- /* Implement the Parcelable interface
- * {@hide}
- */
- public static final Creator<WifiWakeReasonAndCounts> CREATOR =
- new Creator<WifiWakeReasonAndCounts>() {
- public WifiWakeReasonAndCounts createFromParcel(Parcel in) {
- WifiWakeReasonAndCounts counts = new WifiWakeReasonAndCounts();
- counts.totalCmdEventWake = in.readInt();
- counts.totalDriverFwLocalWake = in.readInt();
- counts.totalRxDataWake = in.readInt();
-
- counts.rxUnicast = in.readInt();
- counts.rxMulticast = in.readInt();
- counts.rxBroadcast = in.readInt();
-
- counts.icmp = in.readInt();
- counts.icmp6 = in.readInt();
- counts.icmp6Ra = in.readInt();
- counts.icmp6Na = in.readInt();
- counts.icmp6Ns = in.readInt();
-
- counts.ipv4RxMulticast = in.readInt();
- counts.ipv6Multicast = in.readInt();
- counts.otherRxMulticast = in.readInt();
- in.readIntArray(counts.cmdEventWakeCntArray);
- in.readIntArray(counts.driverFWLocalWakeCntArray);
- return counts;
- }
- /* Implement the Parcelable interface
- * {@hide}
- */
- @Override
- public WifiWakeReasonAndCounts[] newArray(int size) {
- return new WifiWakeReasonAndCounts[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index b4dfac6c01c7..6076175ce9d1 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -102,6 +102,12 @@ public abstract class ProvisioningCallback {
public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14;
/**
+ * The reason code for provisioning failure when the status of a SOAP message is not the
+ * expected message status.
+ */
+ public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15;
+
+ /**
* The status code for provisioning flow to indicate connecting to OSU AP
*/
public static final int OSU_STATUS_AP_CONNECTING = 1;
@@ -147,6 +153,11 @@ public abstract class ProvisioningCallback {
public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9;
/**
+ * The status code for provisioning flow to indicate starting the third SOAP exchange.
+ */
+ public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10;
+
+ /**
* Provisioning status for OSU failure
*
* @param status indicates error condition
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index 5c9df6a0186c..c7993e308d17 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -189,8 +189,7 @@ public class HomeSpTest {
Map<String, Long> homeNetworkIds = new HashMap<>();
byte[] rawSsidBytes = new byte[33];
Arrays.fill(rawSsidBytes, (byte) 'a');
- homeNetworkIds.put(
- StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ homeNetworkIds.put(new String(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
homeSp.setHomeNetworkIds(homeNetworkIds);
assertFalse(homeSp.validate());
}